ProviderTransform.options() does not merge arbitrary provider options into
the merged options object. Read chunkTimeout from item.options as a fallback
so provider.<id>.options.chunkTimeout works as documented.
Addresses kilo-code-bot review finding in PR #9795.
Add chunkTimeout propagation to Vercel AI SDK streamText timeout.chunkMs
for silent stream dropout detection. The config option already existed in
the provider schema and worked at the fetch wrapper level, but was not
passed through to the streamText call. This adds dual-layer protection
at both the fetch layer and the SDK stream consumer layer.
Also updates docs to document chunkTimeout with failure scenario and
recommended values (15-30s).
Update documentation and changesets to specify that BYOK badges
apply specifically to Kilo Gateway models and do not apply to models
selected through other providers.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Remove v2 HTTP API error-schema notes and `opencode login` default
that do not apply to the Kilo fork. Rename OPENCODE_PERMISSION to
KILO_PERMISSION to reflect the correct environment variable.
Introduce a `settle` helper function to improve the stability of visual
regression tests. The function ensures that fonts are loaded, animation
frames have processed, and specific dynamic elements (like code blocks)
have finished rendering before snapshots are taken. This helps reduce
flakiness caused by asynchronous rendering in Storybook.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
The wizard always re-requests migration data via requestMigrationData on
mount, so the data attached to migrationState was never read. Send only
the needed flag and source.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Each wizard mount generated a fresh operationId and left its cached
discovery in the per-provider map forever. Prune entries from abandoned
operations when a new data request arrives, and delete an operation's
entry once its migration finishes.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Split scanTaskStore into a history mode (legacy) that trusts taskHistory
and only stats each conversation file, and a discover mode (Roo) that
enumerates and parses task directories. This restores the prior legacy
behavior of not surfacing on-disk tasks missing from history and avoids
parsing every conversation file during detection.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Provider plugins (llmgateway, nvidia, openrouter, vercel, zenmux) now
verify the provider ID before applying attribution headers, preventing
custom-defined providers sharing the same endpoint URL from being
mutated by built-in plugin logic.
Additional changes:
- Add auth-v2.json migration path for multi-account store continuity
- Remove obsolete @ai-sdk/xai patch and ConsoleCommand registration
- Add native LLM session recordings for anthropic, openai-oauth, and zen
- Update CLI help snapshots to reflect Kilo branding
- Expand i18n with usage-exceeded dialog strings (it, nl, uk)
The models snapshot is now embedded directly in the compiled binary,
eliminating the need for a separate models-snapshot.json file alongside
the CLI executable.
- Delete script/kilocode/models-snapshot.ts build-time preparation
- Delete src/kilocode/provider/models-snapshot.ts runtime loader
- Remove snapshot copy steps from vscode, jetbrains, and opencode builds
- Remove snapshot existence checks from PrepareLocalCliTask/CheckCliTask
- Remove snapshot-related .gitignore and .prettierignore entries
- Simplify watch-cli, local-bin, and build scripts
- Update smoke test error messages to say "embedded" not "sidecar"
- Simplify models-snapshot tests to validate parsing only
- Remove models-snapshot from extract-source-links skip list
Introduce a `metadata` method on SessionProcessor.Handle that buffers
metadata emitted before tool-call registration, then applies it on the
running transition. This decouples metadata emission timing from
tool-call lifecycle.
Downgrade virtua from 0.49.1 to 0.42.3 and migrate the virtualizer API:
- Replace `findItemIndex(scrollOffset)` with `findStartIndex()`
- Replace `bufferSize` prop with `overscan` (count-based)
Additional changes:
- Change Permission.reply return type from Promise<boolean> to Promise<void>
- Make Ruleset type readonly and remove unnecessary array spreads
- Update nvidia provider headers to reference Kilo branding
- Reorder SDK event type definitions for installation events
- Reduce promise facade allowlist in check script
The JetBrains Runtime bundled with IntelliJ ships libfontmanager.so
but expects libfreetype.so.6 and libfontconfig1 on the host system.
The container image currently lacks these, causing UnsatisfiedLinkError
in any test that initialises Swing font metrics.
Install them explicitly until the updated container image (which will
include these packages in the Dockerfile) is available.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
The container image has bun pre-installed but not the project's
node_modules. Gradle's generateOpenApiSpec task runs 'bun dev generate'
which needs drizzle-orm and other packages from node_modules.
Add an explicit 'bun install' step after checkout.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Adapt Kilo-specific code to breaking changes introduced by the v1.15.9
merge:
- Migrate LLM test helpers to use LLMEvent factory constructors instead
of raw event object literals
- Update provider cost extraction from `usage.raw` to native
`usage.providerMetadata` keyed by provider name
- Preserve AI SDK raw usage in providerMetadata for billing continuity
- Replace `findStartIndex()` with `findItemIndex(scrollOffset)` in
virtualizer calls
- Replace `overscan` prop with pixel-based `bufferSize` in virtual lists
- Change provider `all` data shape from array to Map
- Remove `useCommandPalette` dependency, replaced by mode stack pattern
- Fix ToolResultValue schema to avoid circular inference with tsgo
- Add missing test layer dependencies (HttpClient, RepositoryCache,
Command)
- Remove obsolete models-snapshot files
- Fix Permission reply routing tests to expect NotFoundError instead of
boolean false
- Normalize config references and fix nested type narrowing
Nothing imports @hono/zod-validator anywhere in the repo, and its peer dependency hono was removed in #10993, leaving an unmet peer. opencode was the only consumer, so the root catalog entry is dropped too.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
These auto-generated SST type files reference a root sst-env.d.ts that does not exist and import the "sst" package, which was removed in #10993. Kilo is CLI-only with no hosted platform, so these are dead artifacts. The upstream-merge tooling already lists sst-env.d.ts in skipFiles, so they won't be re-added.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Switch the JetBrains unit job to run inside
ghcr.io/kilo-org/build/jetbrains:24.04, which already contains Bun,
Java 21, and the Gradle 9.4.1 distribution pre-cached in
GRADLE_USER_HOME. The three manual setup steps (bun, java, gradle)
are no longer needed and are removed.
A 'Mark workspace as git-safe' step is added after checkout because
container jobs mount the workspace from the host with different file
ownership. Git exit-128 errors otherwise occur when Gradle spawns a
'git tag' subprocess (build.gradle.kts:85).
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
There is no top-level docs/ directory in the repo (docs live under
packages/kilo-docs/, already excluded), so the '!docs/**' entry never
matched anything. Remove the dead filter line.
The layout (auto | stretch toggle) in the Display settings tab was dead
code: the backend schema marks it @deprecated with the note 'Always uses
stretch layout', and the engine ignores the user choice entirely.
Remove the setting from:
- DisplayTab.tsx (UI row + LAYOUT_OPTIONS array)
- Config type (layout field)
- settings-io.ts KNOWN_KEYS allowlist
- All 20 language i18n files (80 translation keys total)
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
kilo-console's ProjectConsoleRoute.tsx imports @opencode-ai/ui/file,
@opencode-ai/ui/context/file, and @opencode-ai/ui/session-review.
The removal was a false positive from depcheck which failed to detect
the workspace package references. Count now 33 deps removed.
- Add packages/containers/jetbrains/Dockerfile extending bun-node with
Java 21 (apt-get, multi-arch safe) and Gradle 9.4.1 pre-cached in
GRADLE_USER_HOME so the wrapper skips the network download
- Register the new image in build.ts (after bun-node, before rust) and
update README
- Fix containers.yml branch trigger: dev → main so images are actually
published from the default branch on every relevant push
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Convert the remaining `Effect.sleep(50)` synchronization hacks in
`prompt.test.ts` to either `Effect.yieldNow` or `waitFor` against
`SessionStatus`, mirroring the pattern already used elsewhere in the
file. Same motivation as the previous commit: stop making correctness
depend on how quickly CI schedules fibers.
- "concurrent loop callers all receive same error result": yieldNow
before resolving the gate, so the queued caller joins the run on a
scheduler turn instead of a 50ms window.
- "loop waits while shell runs ..." / "shell completion resumes
queued loop callers": yieldNow before asserting `llm.calls === 0`
while the shell is still running. The shell is already gated on
`waitFor("shell busy", ...)`.
- "cancel interrupts loop queued behind shell": waitFor shell busy
before forking the loop, then yieldNow before cancelling.
- "shell rejects when another shell is already running": waitFor
shell busy before issuing the second shell call.
The `Effect.sleep(20)` at line 93 is the poll interval inside the
`waitFor` helper itself and is left unchanged.
Storybook addons (addon-docs, addon-a11y, addon-themes) are configured
features, not unused dependencies. Their removal disabled documentation,
accessibility, and theme panels rather than pruning dead code. This restores:
- kilo-ui: addon-docs, addon-themes, addon-a11y
- kilo-vscode: addon-docs, addon-a11y
- .storybook/main.ts configs to their original addon arrays
- knip.json: reverts story file entry point additions (addons serve as
implicit entry points for story files)
Remaining removals (34 deps) are unaffected.
- command.ts: check migrate() return value, count failures, and surface
error count in the completion notification instead of silently ignoring
failed session imports (fixes bot WARNING)
- service.ts: read history_item.json for accurate title, workspace, and
timestamp — falls back to parsing api_conversation_history.json when
the file is absent
- service.ts: add rooveterinaryinc.roo-code and rooveterinaryinc.roo-code-nightly
to the list of Roo Code extension IDs to probe
Currently the `kilo agent create` command generates extremely long agent
descriptions. This is because the system prompt for the `generate` agent
tells it to include multiple verbose examples of when the agent should
be used. This is unnecessary and increases system context bloat without
improving the parent agent's ability to choose a subagent.
This change updates the system prompt to exclude the guidance about
examples, and instead includes official guidance from Anthropic's
documentation on best practices for agent descriptions.
The schedule trigger fires on every repo where the file exists,
including contributor forks. Forks don't have access to
OPENCODE_WATCH_SLACK_WEBHOOK, so the Slack step fails. The previous
vars.OPENCODE_WATCH_ENABLED guard evaluated to true on forks (empty
!= 'false'), so it didn't protect anything.
Add the same github.repository == 'Kilo-Org/kilocode' guard used by
18 other workflows in this repo.
Adds a new VS Code command 'kilo-code.new.importRooCodeSessions' that
discovers and imports conversation history from a Roo Code installation.
- Extend migrate() in legacy-migration/sessions/migrate.ts with optional
overrides (custom dir + pre-resolved LegacyHistoryItem) so the existing
parsing pipeline can be reused without modification for any extension's
tasks directory.
- Add packages/kilo-vscode/src/roo-import/service.ts which locates Roo
Code global storage as a sibling of the current extension's storage, scans
the tasks/ directory, and derives session metadata (title from first user
message, timestamp from numeric task ID).
- Add packages/kilo-vscode/src/roo-import/command.ts with a VS Code quick-pick
+ progress-notification flow.
- Register the command in extension.ts and package.json.
Closes#11243
htmlparser2 was added by upstream but lost during rebase conflict
resolution in packages/opencode/package.json. It is actively
imported at packages/opencode/src/tool/webfetch.ts:3
Story files in webview-ui/src/stories/ were flagged as unused by knip
after storybook addon references were removed from .storybook/main.ts.
Adding them as explicit knip entry points resolves the CI failure.
packages/kilo-ui and packages/kilo-vscode still referenced
@storybook/addon-docs, @storybook/addon-a11y, @storybook/addon-themes
in their addons array after the deps were removed.
MiniMax models (id contains "minimax") were in the variants() exclusion
list, so M3 exposed no reasoning control on any route despite supporting
the Anthropic `thinking` field (type: adaptive | disabled).
Remove minimax from the exclusion list and add instant/thinking variants,
mirroring the glm/kimi/qwen toggle added in #8484:
- @ai-sdk/anthropic (direct provider): map to native
thinking:{type:"disabled"} / thinking:{type:"adaptive"}
- @kilocode/kilo-gateway + @openrouter/ai-sdk-provider: reuse the
reasoning:{enabled} shape, translated by kiloProviderOptions.
Replace the obsolete "minimax returns empty object" test with coverage
for the direct-anthropic and kilo-gateway routes.
Refactor the description for the `settings.models.hidePromptTraining` setting across all supported languages to remove the redundant "across all Kilo clients" phrase, making the text more concise.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
- Add dialog to show docs URL when no display server is detected on Linux
- Simplify dialog to show 'No display detected' with docs URL
- Remove unnecessary browser open attempt in headless environments
- Add kilocode_change markers for new dialog component
The previous implementation tried to open a browser even on headless systems,
which would fail silently. The new dialog clearly communicates the situation
and provides the docs URL for manual access.
Corrects the model identifier to `kilo/openai/gpt-5-nano`. Previously, running the triage agent failed because the prefix was missing, throwing an Model Not Found error. Resolved by explicitly using the `kilo/openai/gpt-5-nano` target path.
Extract isEnterKeyCommitNotIme so PromptInput, docks, selectors, and KiloClaw
inputs share one definition. Bun tests cover Enter, composing, and keyCode 229.
Treat keyCode 229 and isComposing like other stacks so Enter does not send, pick models, rename, or submit docks while an IME is confirming text.
Fixes#7216
* feat(vscode): add agent autonomy presets
* feat(work-style): simplify onboarding state to use config-only persistence and add skipped state
Replace globalState-based `onboardingShown` flag with a new `skipped`
enum value in the `agentWorkStyle` VS Code setting. This makes the
onboarding flow re-triggerable by setting the config back to `unset`
and removes the need for extension context in work-style handlers.
- Add `skipped` to WorkStyleState enum for dismissing without choosing
- Remove `onboardingShown` from messages and context provider
- Add `watchWorkStyleConfig` to reactively push changes to webview
- Extract `SidebarEmptyState` and `WelcomeEmptyState` components from
MessageList for cleaner separation of concerns
- Pass `emptyState` prop through ChatView to allow sidebar-specific
onboarding UI without coupling MessageList to WorkStyleProvider
* chore: update kilo-vscode visual regression baselines
* feat(work-style): refine onboarding preferences
* feat(webview): re-request work style on extensionDataReady if still loading
Add a listener for the extensionDataReady message so that the
WorkStyleProvider retries data fetching when the extension signals
readiness, preventing a stale loading state caused by race conditions
during webview initialization.
* chore: update kilo-vscode visual regression baselines
* feat(work-style): improve onboarding flow
* chore: update kilo-vscode visual regression baselines
* refactor(onboarding): extract work style display logic into pure state resolver
Decouple onboarding visibility from the persisted WorkStyleState by
introducing a dedicated `display` signal driven by
resolveWorkStyleOnboarding(). The onboarding panel now auto-persists
"skipped" on first render (one-off semantics) and dismisses itself on
newTaskRequest events. Unit tests cover the three resolution branches.
* style(welcome): widen responsive breakpoint for work-style empty state
* fix(vscode): make work style onboarding updates reliable
Persist skipped state only after onboarding is bypassed, apply presets through one rollback-aware extension operation, and use the human-in-the-loop identifier consistently.
* fix(work-style): remove duplicate payload post after apply handler
The apply handler already posts the updated work-style payload
internally, so the additional post here caused a redundant message
to be sent to the webview after each style application.
* refactor(onboarding): relocate settings access from toast into picker card
Move the "Go to Settings" call-to-action out of the post-save toast
and into a persistent inline link at the bottom of the WorkStylePicker.
Simplify the success toast to a short 2-second confirmation, tighten
choice descriptions for conciseness, drop the bash detail row, and
remove the small-viewport rule that hid mode details.
* chore: update kilo-vscode visual regression baselines
---------
Co-authored-by: Imanol Maiztegui <imanol.mzd@gmail.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
- Replace 'Review only these things:' with an explicit statement that
the six tracks are permitted topics but not all are spawned for every
review, removing the contradiction with the tiered sub-agent system
- Align track names (duplication, dead code) between Review Focus and
Required Workflow step 3 so both sections use the same identifiers
- Scope the deploy safety, duplication, and dead code rules to their
respective tracks with 'apply only when this track is active' so they
don't imply mandatory coverage when those tracks are not spawned
* fix(vscode): render streaming assistant rows outside virtualizer to prevent layout jumps
Replace the `keepMounted` index-based approach with a direct rendering
suffix for active assistant turns. Rows belonging to the streaming turn
are partitioned out of the virtualizer and rendered as plain DOM elements,
eliminating measurement instability caused by rapidly growing content
while preserving virtualized history for completed turns.
* Update packages/kilo-vscode/webview-ui/src/components/chat/MessageList.tsx
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
* fix(vscode): complete direct row ID rename
* refactor(transcript-rows): restrict direct partition to only the latest visible turn
Simplify partitionRows so that older streaming turns are no longer
retained in the direct (non-virtualized) output once a newer turn
becomes visible. The lookup now checks only the final row's turn
against the direct set, ensuring completed assistant turns move back
into the virtualizer immediately when the conversation advances.
---------
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
Small diffs (<100 LOC, ≤3 files) now use 1-2 sub-agents instead of always
spawning six, reducing cost for simple changes. Medium diffs (100-300 LOC)
use 3-4, and large/complex diffs retain the full six-agent workflow.
On Windows, PowerShell commands with non-ASCII characters (e.g., Chinese, Japanese, Cyrillic) produce garbled output (mojibake) because the console encoding defaults to the system OEM code page rather than UTF-8.
Switch from `-Command` to `-EncodedCommand` with a Base64-encoded UTF-16LE payload that explicitly sets `[Console]::InputEncoding`, `[Console]::OutputEncoding`, and `$OutputEncoding` to UTF-8 before executing the original command. This ensures both input and output are properly encoded as UTF-8 regardless of the system locale.
Fixes#4138Fixes#2422Fixes#2939
When `kilo console --port 4321` reuses an already-running daemon on a
different port (e.g. 4097), the new options were silently ignored. Now
`kilo console` checks if the running daemon matches the requested
host/port, and restarts if they differ.
The restart only occurs when explicit `--port` or `--hostname` options
are provided via CLI, not when using default values.
Print a yellow non-fatal warning when kilo console or kilo daemon
start/restart is invoked with an explicit --port outside 4097-4116.
Auto-discovery only scans that window, so an out-of-range port can
silently break later manual or auto-connect attempts.
Implementation stays entirely in Kilo-owned files to avoid touching
upstream shared code:
- Added packages/opencode/src/kilocode/cli/port-warning.ts helper
exporting warnPort(port), which skips port 0 (auto-pick) and emits
a yellow console.warn when the explicit port is outside
Daemon.PortRange.
- Hooks the helper from console.ts and daemon.ts (start/restart)
The command still succeeds; the warning is informational only.
Reads terminal.integrated.fontFamily and terminal.integrated.fontSize (with
editor font fallback) instead of the editor font CSS var. A config watcher
broadcasts fontChanged messages so live terminals update without a reload.
Nerd Font glyphs now render correctly in Agent Manager terminal tabs.
Keys are stripped from provider payloads before they reach the webview,
so the model-fetch request for an existing provider always went out
unauthenticated and gated endpoints returned 401. Retain providerID->key
extension-side in fetchProviderData, send providerID from the dialog when
the key field is untouched, and resolve the stored key in the fetch
handler — only when the requested URL matches the provider's configured
baseURL, so a stored secret can never be redirected to a different host.
Addresses the API-key half of #10139.
Split scroll-related concerns into smaller, focused units:
- Move user interaction detection (pointer, key, touch, wheel) into
a new `createUserActivity` hook with mark/consume/isRecent API
- Extract `distanceFromBottom` and `canScroll` as pure utility helpers
- Simplify `createAutoScroll` by replacing inline state and event
handlers with the composable user activity tracker
- Rename internal actions for clarity (scrollToBottom → follow/force)
* feat(vscode): add category labels and clarify command titles in package.json
Add "Kilo Code" category to all command contributions for better
organization in the VS Code command palette. Clarify the "Open in Tab"
command title to be more descriptive instead of generic "Kilo Code".
This improves discoverability and user experience when browsing available
commands in VS Code.
* chore: add command palette changeset
---------
Co-authored-by: Sylwester Liljegren <sylwester.liljegren@softronic.se>
Co-authored-by: Johnny Amancio <johnnyeric@gmail.com>
Remove logic that automatically unpaused scroll when the container
temporarily stopped overflowing. Previously, layout changes that reduced
content height below the viewport would reset the userScrolled flag,
causing the chat to jump back to the bottom when the user had
intentionally scrolled up.
The stop/pause function now accepts a force parameter to bypass the
canScroll check, ensuring an explicit user pause is never cleared by
transient layout changes.
Remove the `isNested` helper that previously allowed upward scrolling
inside nested scrollable regions (tool output, code blocks) without
disabling auto-scroll. Now any upward wheel input anywhere in the
transcript immediately pauses auto-scroll, reflecting the user's intent
to review earlier content even when a nested region would consume the
event.
The wheel handler is registered with `capture: true` so it fires before
nested elements can intercept the event, and `markUser` no longer
triggers on wheel events since the capture handler handles that intent.
The compat re-export and the build's CJS-redirect plugin only existed to work
around the 'G9' crash that's actually a Bun --splitting bug (now fixed by
splitting:false). With splitting off the morphsdk ESM barrel bundles cleanly,
so import it directly in warpgrep.ts and remove the indirection.
The real cause of the 'Exported binding G9 needs to refer to a top-level
declared variable' SyntaxError is a Bun 1.3.14 --splitting codegen bug
(oven-sh/bun#25621), not @morphllm/morphsdk. With splitting:true Bun emits
invalid cross-chunk re-exports (import{vn as G9}) that crash the compiled
baseline binary at startup. Disabling splitting produces a valid binary;
verified the 'as G9' artifact is gone from the compiled output.
The morphsdkCjsPlugin called require.resolve on the raw dist/.../client.cjs
path, which is not an exported subpath in the package's exports map, so Bun
aborted the release build with 'Cannot find module ...client.cjs'.
Resolve through the public specifier @morphllm/morphsdk/tools/warp-grep/client
instead — require.resolve uses the package's "require" condition, mapping it
straight to client.cjs.
The createRequire approach from #10955 did not prevent the Bun ESM
splitter from generating invalid output. Bun 1.3.14 with
`conditions: ["browser"]` resolves @morphllm/morphsdk via the "import"
condition (pre-split ESM barrel) even inside createRequire() calls,
pulling in 52 chunk-*.js files that cause:
SyntaxError: Exported binding 'G9' needs to refer to a top-level declared variable.
Fix: add a morphsdkCjsPlugin in script/build.ts using Bun's onResolve
API to redirect the module specifier to the absolute path of client.cjs
before the ESM splitter is invoked. client.cjs is a self-contained
~2300-line CJS bundle with no chunk-*.js imports.
morphsdk.ts is simplified to a plain re-export — the CJS redirection
happens at build time, no source-level workaround needed.
Two independent release validation failures introduced by kilo-opencode-v1.14.33 (morphsdk) and the new all-arch validation jobs.
**@morphllm/morphsdk pre-split ESM (intermittent SyntaxError on Windows)**
@morphllm/morphsdk/tools/warp-grep/client ships as a 805-byte ESM barrel that
re-exports from 13 internal chunk-*.js files (52 chunks total). When Bun 1.3.14
bundles the CLI with splitting+minify enabled, merging these external pre-split
chunks into its own chunk graph intermittently produces invalid minified ESM:
SyntaxError: Exported binding 'G9' needs to refer to a top-level declared variable.
Non-deterministic because Bun's parallel bundler uses different orderings per run;
same build sometimes succeeds, sometimes fails on Windows x64.
Fix: load morphsdk via createRequire (forces CJS bundle, client.cjs 2292 lines,
self-contained) instead of the ESM barrel. Wrapper lives in kilocode/compat/ with
a comment explaining how to detect and fix this pattern for future third-party deps.
Scanned all 40+ third-party packages imported by packages/opencode/src — morphsdk
is the only one with pre-split ESM; all others ship single-file ESM or CJS only.
**Alpine musl validation (libstdc++/libgcc missing)**
Bun's musl target (bun-linux-{arch}-musl) is not fully static — it links against
libstdc++.so.6 and libgcc_s.so.1 (GCC C++ runtime). Alpine base does not ship
these by default. The fix adds apk add --no-cache libstdc++ libgcc at the start of
the Alpine Docker smoke test, matching the runtime requirement that any Alpine user
of the CLI would also need.
The previous docs stated Security Agent was restricted to Teams and
Enterprise plans, which no longer matches the product behavior.
The personal and organization sidebars both expose Security Agent
unconditionally, with no plan gate or feature flag. This keeps the
docs aligned with that behavior.
Reason for change: docs were out of sync with UI/backend access rules.
Wrap the WorkingIndicator in a persistent slot container with a fixed
min-height so that toggling between the spinner and session actions
does not cause the chat content to jump. This stabilizes the scroll
position when live output finishes.
Extract helper utilities to identify interactive elements (buttons,
inputs, textareas, contenteditable) and nested scrollable containers.
Skip pausing auto-scroll when the user interacts with form controls
or question answer elements, preventing false positives that would
stop the chat from following new content.
Replace the custom event approach for resuming auto-scroll when the
permission dock disappears. Instead, observe the scroll container's
dimensions directly via createResizeObserver in the auto-scroll hook,
eliminating the coupling between ChatView and MessageList through
window events. The scroll ref is now tracked in the store to enable
resize observation alongside the existing content observer.
Remove lastScrollTop tracking that incorrectly classified virtualization
and layout-driven scroll position changes as user-initiated scrolling.
Now only explicit user input (detected via recentlyInteracted()) can
pause the auto-scroll following behavior, keeping chat pinned to the
bottom during programmatic or layout-driven updates.
Aligns the VSCode extension and kilo-ui with the JetBrains plugin, which
replaced the brain-circuit icon with the book-open-check icon for the
'may be used for training data' indicator in the model picker.
* Add Atomic Chat as a first-class local provider.
Ship the atomic-chat plugin with auto-discovery on localhost:1337, register the provider in models.dev fixtures, and document setup for VS Code and CLI.
* Remove dead code
Removed atomicChat provider mapping from legacy migration.
* Update Atomic Chat provider icon to theme-colored vector.
Replace the embedded raster icon with a currentColor SVG symbol so it matches provider icon styling and inherits UI color consistently.
* Allow optional API key for local Atomic Chat and LM Studio providers.
Load the atomic-chat plugin despite named constant exports, register local-server auth in the plugin, and let CLI and VS Code connect with an empty key on localhost.
* Gate Atomic Chat discovery behind explicit opt-in
* Update packages/plugin-atomic-chat/src/utils/should-probe-atomic-chat.ts
* Remove dead branch in atomic-chat model ref probe.
Drop the modelID check (never equals provider key) and the duplicate providerID branch.
* Fix PR CI: register atomic chat plugin and complete i18n.
Restore atomic-chat in default-plugins after main merge, add missing sidebar locale keys, and annotate shared upstream diffs.
* Format i18n locale files and ProviderConnectDialog with Prettier.
* Address PR review: docs order, narrow annotations, plugin fixes.
Reorder local-models providers per maintainer feedback; use inline kilocode_change markers in dialog-provider. Share ModelStatusCache, fix config discovery abort/timeout, throw on fetch failure, and resolve bot review warnings.
* Align dialog-provider with upstream keymap bindings after rebase.
Restore useBindings instead of useKeyboard so shared-file diff stays minimal and passes annotation checks.
* Update packages/kilo-vscode/webview-ui/src/components/settings/ProviderConnectDialog.tsx
* Deduplicate Atomic Chat /v1/models fetch on config discovery.
Use a single shared models endpoint request in enhanceConfig instead of separate health and discovery calls.
* Fix kilo-code-bot review: import provider key and log cache errors.
Export ATOMIC_CHAT_PROVIDER_KEY from local-providers for the webview, log cache warm failures, and throw on network errors in fetchModelsEndpoint.
* fix(plugin-atomic-chat): harden discovery and reduce chat toasts
Reuse auto-detect model list to avoid duplicate /v1/models calls, wire AbortSignal into fetch, replace silent catches with logging, and only surface validation errors in chat.params.
* fix(plugin-atomic-chat): refresh model cache on chat validation retries
Bypass the 15s model list cache after the first failed attempt so retryWithBackoff can observe newly loaded models.
* Update packages/plugin-atomic-chat/src/utils/index.ts
* fix(plugin-atomic-chat): repair categorizeError not_found branch
Restore return statement and map "not loaded" validation errors to not_found after bot commit broke the if block.
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
* feat(marketplace): extract marketplace into standalone webview panel
* fix(marketplace): correct fetchData directory arg and add error logging
Replace swallowed catch block with console.warn for session status
sync failures, and pass `this.directory()` instead of `project` as the
second positional argument to `fetchMarketplaceData`.
Update Bun runtime and type definitions across the repository:
- package.json packageManager field
- @types/bun in root and script/upstream
- Nix flake pinned binary with updated hashes
- Container Dockerfile ARG
- Documentation and story fixtures referencing the version
Extract java-kotlin language analysis from the shared CodeQL Advanced
workflow into a dedicated codeql-kotlin.yml workflow. This allows the
Kotlin analysis (which requires Java, Gradle, and a manual build) to
run independently with path filtering on packages/kilo-jetbrains,
reducing unnecessary CI runs for unrelated changes.
- Add new codeql-kotlin.yml with path-scoped triggers
- Remove java-kotlin from the matrix in codeql.yml
- Simplify codeql.yml by removing conditional Java/Gradle setup steps
- Register codeql-kotlin.yml in check-workflows.ts active set
Replace the fragile covered/uncovered prefix dedup in SessionController with a stateless content-overlap glue: a text/reasoning delta only appends the portion that extends the current model tail. This eliminates the token-doubling (e.g. "importimport", "ReadRead a file") that occurred when multiple PartUpdated snapshots landed before the lagging PartDelta stream caught up.
Also adds a MdViewHybrid fast path that grows the trailing code view in place while inside an open fenced code block, skipping the full commonmark re-parse and block diff per token, with html() recomputed lazily when stale.
* feat(session-export): scaffold module with config constants
* feat(session-export): add zstd compression wrapper
* feat(session-export): event and envelope type definitions
* feat(session-export): eligibility check with kill-switch
* feat(session-export): org signal collector with auth resolver
* feat(session-export): worker SQLite schema and storage helpers
* feat(session-export): content-addressed chunker with zstd dedup
* feat(session-export): client-side light scrubber
* feat(session-export): IPC contract and inbox with back-pressure
* feat(session-export): persist scrubbed events with chunked payloads
* feat(session-export): worker entry point with inbox drain loop
* feat(session-export): main-thread capture module
* feat(session-export): workspace baseline and delta fibers
* feat(session-export): sync subscriber and tool io chunking
* feat(session-export): bootstrap wiring and compaction hook
* feat(session-export): wire capture hooks into sessions
* feat(session-export): uploader and buffer cap
* chore(session-export): annotate shared session hooks
* changeset(session-export): add release note
* fix(session-export): keep bootstrap non-blocking without instance context
* feat(session-export): respawn worker after failures
* test(session-export): add performance budget assertions
* test(session-export): add worker end-to-end smoke test
* fix(session-export): strip identity and high-risk baseline paths
* test(session-export): gate perf assertions for stable sweeps
* fix(session-export): bundle worker in single-file builds
* fix(session-export): make capture envelopes cloneable
* fix(session-export): drain worker on CLI shutdown
* feat(session-export): capture workspace baseline and deltas
* fix(session-export): preserve request metadata
* test(session-export): cover request metadata capture
* feat(cli): send indexed session export batches
* feat(cli): authorize session export uploads
* fix(cli): flush session export shutdown uploads
* feat(cli): optimize session export replay payloads
* fix(cli): include session export surface metadata
* fix(session-export): decrement chunk refs after upload
decRefChunks was never called, so chunk ref_count stayed at 1 (or
higher with dedup) and DELETE FROM chunk WHERE ref_count <= 0 never
matched. Chunks accumulated in the local SQLite buffer until the 50 GB
cap. Call decRefChunks alongside markUploaded so deleteUploaded can
reclaim the rows.
* fix(session-export): add periodic uploader flush timer
flushIntervalMs and retryBackoffMaxMs were both defined in config and
neither was referenced anywhere; scheduleFlush only ran on inbound
events or reconnect. After a 5xx or network failure the row was backed
off for 1 s, but if no further event arrived the retry never fired and
the events stranded until the CLI restarted. Drive a periodic flush
from a setInterval, unref the handle so it doesn't pin the process, and
clear it from a new dispose() hook the worker calls on shutdown.
* fix(session-export): stop emitting absolute workspace root in baseline
CaptureMetadata.root was the literal absolute filesystem path
(/Users/<name>/Projects/<repo>), shipped in every
workspace_baseline_completed event and not stripped by handlers'
identity filter. The field was set but never read anywhere downstream
— file paths in the baseline are already relative, so the root added
no replay signal. Remove the field outright.
* fix(session-export): cap pendingEvents result set
The SELECT had no LIMIT clause, so under a backlog (network outage,
crashed receiver) it would materialize the full pending table into a
JavaScript array before the byte-limit truncation applied. With a
50 GB buffer cap that is hundreds of MB of heap inside the worker per
drain. Add LIMIT 500 — the drain loop already re-queries until empty,
so no events are missed.
* fix(session-export): exponential retry backoff up to retryBackoffMaxMs
Both the 5xx and network-error branches always retried after the floor
delay regardless of how many attempts had already failed, and
retryBackoffMaxMs was unreferenced. During a sustained outage every
session re-tried at roughly 1 Hz against the dead receiver. Surface
upload_attempts on EventRow and compute the next delay as
min * 2^attempts capped at max.
* fix(session-export): evict superseded workspace snapshots on remember
createWorkspaceProvider retained every captured snapshot — in-memory
and inside the persisted state file — even after the session moved on
to a newer one. For a 1k-file repo over a 100-turn session that is
~2 GB of unreachable heap plus a state file that grows monotonically.
Drop the previous snapshot for the session on remember() when no other
session still references it.
* fix(session-export): anchor aws_secret_key scrubber to key name
The bare 40-char base64 pattern matched every 40-character hex string,
including all git commit SHAs. Tool outputs, diffs, and conversation
messages were silently rewritten as <<REDACTED:aws_secret_key>>,
destroying lineage information in training data. Require the key name
context — naked secrets in unstructured text are rare and the .env /
.aws/credentials high-risk path strip already covers the common case.
* fix(session-export): preserve root linkage in SyncSubscriber events
SyncSubscriber hardcoded rootSessionId = sessionId on every tool,
permission, and feedback event, so sub-agent sessions lost their root
linkage and a future training pipeline could not reconstruct the
agent topology from these side-channel events. Expose the rootSessionId
mapping from Capture and plumb it through the same pattern as
getTurnId.
* fix(session-export): atomic chunk GC after upload
markUploaded + decRefChunks + deleteUploaded were three separate SQL
statements; a crash between markUploaded and decRefChunks would leave
events flagged uploaded (never retried) and chunks with stale
ref_count (never reclaimed by deleteUploaded). Bundle the three calls
into a single transactional commitUploaded helper so either all three
land or none of them do.
* fix(session-export): wait on transient sqlite locks
* fix(session-export): snapshot current workspace directory
* fix(cli): preserve Kilo model export metadata
* fix(cli): send anon id for session export
* fix(cli): fallback to telemetry anon id
* chore(cli): annotate session export config test
* chore: remove session export docs
* fix(cli): harden session export uploads
* fix(cli): preserve stream lifecycle for session export
* fix(kilo-docs): exclude session export ingest link
* fix(cli): restrict session export workspace sync to git repos
* chore: remove session export changeset
* fix(cli): tighten session export payload types
* fix(cli): type session export model payloads
* fix(cli): simplify session export cleanup
* fix(cli): avoid session export shutdown race
* refactor(cli): use drizzle for session export storage
* fix(cli): finalize session export sqlite statements
* fix(cli): link compaction exports to root sessions
* fix(cli): stop exporting raw stream parts
* fix(cli): prune stale workspace snapshots
* refactor(cli): clarify chunk ref counting
* test(cli): clarify dropped upload assertions
* ci: avoid visual path filter action failure
* fix(cli): preserve in-flight workspace snapshots
* fix(cli): stop uploading baseline start events
* fix(cli): trim redundant export metadata
* fix(cli): trim workspace export bookkeeping
* fix(cli): fold terminal outcome into tool exports
* fix(cli): dedupe request context in export batches
* fix(cli): normalize compaction export payloads
* fix(cli): avoid duplicate tool result exports
* test(cli): align session export expectations
* fix(cli): run secretlint during session export scrubbing
* fix(cli): keep retried export batches contiguous
* fix(cli): include agent info in session exports
* fix(cli): flush pending session exports on serve startup
* fix(cli): drop exports when scrubbing fails
* fix(cli): narrow secretlint value extraction
* fix(cli): limit exported agent info
* test(cli): remove brittle agent export source assertion
* fix(cli): ignore corrupt session export workspace state
* fix(cli): keep session export close best effort
* fix(cli): avoid following session export symlinks
* fix(cli): preserve session export chunk ref counts
* fix(cli): retry transient session export uploads
* fix(cli): validate session export ingest endpoint
* fix(cli): tolerate missing export token details
* fix(cli): fail closed on session export org lookup
* fix(cli): decode session export permission replies
* fix(cli): finalize session export on stream close
* fix(cli): bound session export baseline timeout
* fix(cli): avoid persisting workspace file contents
* fix(cli): bound workspace snapshot capture
* fix(cli): validate session export worker messages
* fix(cli): revoke stale session export eligibility
* fix(cli): scope session export workspaces
* fix(cli): extend session export shutdown flush
* fix(cli): infer free Kilo models for export
* fix(cli): avoid duplicate chunk refs
* fix(cli): throttle session export uploads
* fix(cli): harden session export capture
* feat: disclose free model data collection (#10767)
* feat: disclose free model data collection
* chore(cli): document free model footer sorting
* fix(vscode): add free model data translations
* fix: simplify free model data label
* fix: simplify data collection badges
* fix: remove duplicate model info disclosure
* fix: restore composer data tooltip
* fix: align jetbrains data collection indicator
* fix: align free model data indicators
* fix(vscode): show data collection in model preview
* fix: limit data indicators to kilo gateway
* test(cli): relax prompt cancel timeout
* test(cli): annotate prompt cancel timeout
* test(cli): classify prompt queue runtime test
* fix(cli): defer session export startup
* refactor(vscode): extract editor actions from provider
* refactor(vscode): use direct import for DiffVirtualFile type
Replace inline dynamic import type assertion with the already-imported
DiffVirtualFile type at the top of the file.
Reorder statements in KiloBackendAppService and KiloBackendWorkspace so
that warning/error logging occurs before the reactive state is updated.
This ensures observers reacting to state changes can rely on warnings
already being recorded in logs.
* fix(cli): route share links through Kilo session API
Refactor shareSession and unshareSession to return Effect values using
EffectBridge.fromPromise and replace the ShareNext dependency in
SessionShare with KiloSession calls so CLI-generated share URLs point
to app.kilo.ai/s/ public links.
* test(session-share): replace EffectBridge usage with direct Storage service calls
Update session-share test to use Storage.Service directly instead of
wrapping Storage.write in EffectBridge.fromPromise, aligning test code
with the refactored service-based architecture. Add Storage.defaultLayer
to the test effect layer composition.
Migrate all Session.* promise-based helper usage (create, get, messages,
updateMessage, updatePart, setPermission, children, fork) to direct
Effect service consumption via Session.Service. This eliminates the
makeRuntime-backed legacy promise wrappers from session.ts and updates
all dependent modules and tests to use the Effect-based interface.
Key changes:
- Remove exported promise helpers (create, get, messages, etc.) from
session/session.ts along with the module-level makeRuntime instance
- Update kilo-sessions, remote-sender, allow-everything permission,
plan-followup, recall tool, and fork module to yield Session.Service
- Convert remapChildren from async function to Effect generator
- Add PlanFollowupRuntime.session helper for effectful session access
- Update all affected test files to use Effect.runPromise with
Session.Service.use pattern
- Remove session/session.ts from the promise facade allowlist and
update test allowlist counts accordingly
The bundled Shiki worker is created only from its injected webview resource URI, and Pierre does not construct blob-backed workers. Restrict worker-src to the webview source and lock the narrower policy in unit coverage.
The webview worker adapter is reached through an esbuild alias rather than a TypeScript import, so Knip must treat it as an explicit entrypoint for the VS Code CI check to pass.
Document the patch-bounded rendering requirement and correct Chrome trace attribution so future optimizations do not reintroduce full-file gray placeholders or mistake profiler delivery threads for execution threads.
Eager review rendering must not rebuild complete before/after contents when a tiny patch occurs inside a large source file. Preserve existing unified patches through Changes sources, parse them behind the deferred visibility gate, and use eager rendering only for patch-backed detail so gray placeholders clear without regressing session switching.
Diff syntax highlighting ran synchronously on the webview main thread because the Shiki worker was stubbed out (the webview CSP blocked workers), so scrolling large diffs froze the UI. Bundle the Shiki worker as a dist asset, load it from an injected webview URI, and allow it via a scoped worker-src CSP directive so highlighting runs off the main thread. With highlighting off-thread, normal-sized review files now render their diffs eagerly instead of going through Pierre's per-instance virtualizer, which avoids the re-render-all storms that rebuilt thousands of rows on every height change. Large files and an aggregate per-review budget keep eager DOM bounded.
Per-directory AGENTS.md files are dynamically loaded when the agent
reads files in that directory, not pre-loaded at session start. This
is injected as <system-reminder> tags during file access, providing
context-sensitive instructions for monorepos and large projects.
* refactor(opencode): remove legacy Provider promise wrappers in favor of Effect service usage
Replace static `Provider.list`, `Provider.getModel`, `Provider.getLanguage`,
`Provider.getSmallModel`, and `Provider.defaultModel` promise helpers with
direct `Provider.Service.use()` calls through `AppRuntime.runPromise`. This
eliminates the `makeRuntime` import and the wrapper functions that bypassed
the Effect dependency injection system.
- Remove legacy promise helpers from provider.ts
- Update kilo-sessions, roll-call, commit-message, enhance-prompt, and
task tool to use Provider.Service via AppRuntime directly
- Thread Provider.Interface into KiloTask.select for proper DI
- Add Provider.defaultLayer to test layers that exercise TaskTool
- Update commit-message tests to spy on CommitMessageRuntime.model()
* docs(sdk): regenerate v2 SDK types and update edit endpoint description
LanceDB infers the value column type from the first row in _createMetadataData().
Since vector_size (1024) was stored as a number, all subsequent string values
(embedding_provider, embedding_model_id) and booleans (indexing_complete) were
silently coerced to NaN/0/1, corrupting metadata.
On restart, _getStoredEmbeddingProfile() received NaN values, causing
needsRecreation=true every time — the database was dropped and recreated,
the file-hash cache cleared, and a full re-index triggered on every VS Code reopen.
Store all metadata values as strings to ensure consistent column type.
* feat(i18n): support Italian in desktop app
Add Italian translations for the app, shared UI, and Kilo-specific strings.
Register the Italian locale in the app language picker.
* feat(vscode): add Italian language support
* fix(i18n): polish Italian translations
* fix(i18n): complete Italian translations
* style(vscode): format Italian locale files
* fix(i18n): add DeepSeek Italian provider note
---------
Co-authored-by: Johnny Amancio <johnnyeric@gmail.com>
When a shell command has a descriptive title (the parameter
provided by the AI), include it in the permission approval dialog so users
can identify what the command will do, not just see the raw command string.
* fix(tui): dedupe solid-js and @opentui/solid to fix "No renderer found" startup crash
The bundled CLI shipped with two copies of solid-js and two copies of
@opentui/solid since 7.2.1. Each duplicated copy of solid-js and
@opentui/solid creates its own RendererContext token via createContext(),
so the context provided by render() (using one copy) is invisible to
useRenderer() calls resolved against the other copy. A reactive setStore
early in boot triggers a cascade that crosses the copy boundary and
explodes with "Error: No renderer found", preceded by the warning
"You appear to have multiple instances of Solid."
Two duplications were responsible:
1. solid-js: @opentui/solid@0.1.87 declares an exact "solid-js": "1.9.9"
dependency, so bun installed a nested solid-js@1.9.11 inside
node_modules/@opentui/solid/node_modules while the rest of the
workspace used the catalog solid-js@1.9.12 at the top level. Force
dedupe via a root override.
2. @opentui/{core,solid}: packages/kilo-gateway pinned dev/peer
versions to 0.1.75 while opencode used 0.1.87. With kilo-gateway's
tui module imported by opencode in 7.2.1+, both versions were
bundled side-by-side. Bump kilo-gateway's pins to 0.1.87 to match.
Verified locally with a --single build on macOS arm64: pre-fix the binary
crashes on startup with the Solid error; post-fix it boots cleanly. Bundle
shrinks ~16KB from removing the duplicated solid-js copy.
* fix: Upgrade stale version with catalog:
---------
Co-authored-by: Brendan DeBeasi <brendandebeasi@users.noreply.github.com>
Co-authored-by: Johnny Amancio <johnnyeric@gmail.com>
The foo/bar/baz good/bad examples didn't illustrate the rule (just
shorter nonsense vs. longer nonsense). Replace with prose that points
at the canonical 'Naming Enforcement' block, which already lists
realistic preferred names and anti-examples.
* docs: add free and budget model picks to model selection guide
Closes#7038. Links to Auto Model Free and Using Kilo for Free pages.
* docs: address review warnings for model pricing accuracy
* fix: remove stale models table
* Apply suggestions from code review
Co-authored-by: Johnny Amancio <johnnyeric@gmail.com>
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
* feat: Add support for native agents from marketplace instead of modes
* chore: update kilo-vscode visual regression baselines
* fix: add guard for case when user has pre-existing agent with same name
* chore: Clean up unused code
* chore: continue clean up of old code related to modes
* chore: add notification message informing users about migration from modes to agents
* fix: fix broken layout of remove dialog and update leftover mode string
* fix: adjust strings with mode string instead of agent
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
config.get() returns the merged effective value, so a workspace-level pin
or the schema default would falsely look like a stored global default.
Switch to config.inspect().globalValue so the migration only acts on
values actually stored in user settings, and update the test stub to
model scoped values.
Looking up by provider+model id instead of relying on array index makes
the default robust to reordering of the AUTOCOMPLETE_MODELS list, and
fails loudly at module load if the referenced entry is ever removed.
Adds a test asserting the default resolves to a real entry.
The migration cleared pinned default settings before the manager's first
readSettings() call, but firing it as a void promise let the manager's
constructor (which kicks off load() synchronously) race with the migration.
Awaiting the migration in registerAutocompleteProvider ensures the cleared
state is visible when the manager loads.
Aligns the autocomplete model selector with the small/subagent/per-mode
model selectors by exposing a 'Not set (use server default)' option.
Users who pick it follow future default-model changes automatically;
users who explicitly pin a model keep their selection.
Also runs a one-time migration that clears
`kilo-code.new.autocomplete.{provider,model}` when they exactly equal
the current `DEFAULT_AUTOCOMPLETE_MODEL` (Codestral via Kilo Gateway).
Many users have these stored only because it was the only thing visible
in the dropdown; without this they would stay pinned to the current
default and miss future improvements.
* fix(vscode): improve suggest bar responsiveness
Add min-width and text wrapping for action buttons and introduce a
responsive layout that stacks the suggest bar vertically on narrow
viewports.
* chore: update kilo-vscode visual regression baselines
* docs(mistral): update Codestral documentation link
Replace outdated code_generation capabilities URL with current
vibe/code/overview path in the Mistral provider documentation.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Adds a new "Mercury Next Edit via Kilo Gateway" autocomplete model so
users can get Next Edit predictions through their Kilo account without
needing a separate Inception API key. The gateway proxies to the
new /api/nextedit/completions endpoint added in cloud#3516.
Extract KiloModelsService from model-cache to enable dependency injection
and rewrite test files to use Layer-based test harnesses instead of
process-wide mock.module() calls that caused flaky cross-test pollution
on CI.
* refactor(opencode): remove raw LLM interface in favor of stream-based text helper
Introduce KiloLLM.text() to consume Effect streams and extract text
while propagating error/abort events. Replace all usages of the removed
LLM.raw() method and the legacy LLM.stream() async wrapper with
dedicated runtime helpers (CommitMessageRuntime.generate,
PlanFollowupRuntime.handover) that leverage the new stream-based
approach.
- Add KiloLLM.text() stream combinator in kilocode/session/llm.ts
- Remove Interface.raw and the exported LLM.stream() async function
- Refactor commit-message generation to use CommitMessageRuntime
- Refactor plan-followup handover to use PlanFollowupRuntime.handover
- Update all test LLM mocks to remove raw() stubs
- Add unit tests for KiloLLM.text() covering text joining, error
propagation, and abort handling
* feat(skill): migrate Skill module to Effect service pattern and remove legacy promise wrappers
Remove the makeRuntime-based promise helpers (Skill.all, Skill.get,
Skill.dirs) from the skill module and convert the builtin-skills test
suite to use Effect generators with the testEffect harness.
- Delete legacy runPromise wrappers from packages/opencode/src/skill/index.ts
- Rewrite builtin-skills.test.ts to use testEffect and Effect.gen
- Replace WithInstance.provide/tmpdir with TestInstance yield pattern
- Use Skill.Service directly within Effect generators for all assertions
* refactor(session-status): drop makeRuntime promise helpers and wire Service through Effect context
Replace the standalone `SessionStatus.list`, `.get`, `.set` promise
wrappers with direct `SessionStatus.Service` usage via Effect generators
and `AppRuntime.runPromise` at Kilo callsites that remain imperative.
- Remove makeRuntime-based exports from session/status.ts
- Update kilo-sessions.ts and plan-followup.ts to use AppRuntime.runPromise
with SessionStatus.Service
- Thread SessionStatus.Service as a dependency through SuggestTool and
ToolRegistry layers
- Replace spy-based mocks in suggestion tool tests with an in-memory
service stub for deterministic assertions
Match classic autocomplete's policy of never sending absolute fsPaths
upstream. Mercury only needs the path for language/context hints, and
the workspace-relative form is what recentlyViewedSnippets already uses.
* refactor(opencode): migrate ModelCache and Config to effect-native services
Remove legacy async wrapper functions from Config module and convert
ModelCache from a stateful namespace with module-level Maps into a
proper Effect service with Context/Layer semantics.
Key changes:
- Delete Config's `makeRuntime`-based async wrappers (get, getGlobal,
update, warnings, etc.) — all callsites now use
`Config.Service.use(...)` through AppRuntime
- Rewrite ModelCache as an Effect service with HttpClient dependency
injection, replacing imperative Map-based caching with Effect-native
Ref cells and TTL logic
- Convert KiloSessions.init and KilocodeBootstrap.init into proper
Effect services with Layer-based dependency injection
- Wire ModelCache.Service into AppLayer, ProviderAuth, ModelsDev, and
HTTP API handler layers
- Update Permission.layer to depend on Config.Service directly instead
of calling Config async wrappers
- Add new test files for KiloSessions and ModelCache Effect integration
- Remove stale Config.get spyOn mocks from tests that no longer need
them (experimental-session-list, recall)
- Fix indexing-auth to use typed IndexingConfig parameter instead of
untyped record access
* fix(model-cache): resolve race conditions in concurrent fetch and cache invalidation
Introduce versioned cache cells with proper key derivation to prevent
stale responses from overwriting fresher data during concurrent fetches.
- Add version tracking to detect and discard outdated fetch results
- Derive cache keys from provider-specific options (baseURL, token, apiKey)
to isolate concurrent requests with different credentials
- Make ModelCache.clear async to properly await invalidation across layers
- Update OrganizationDeps.clear signature to allow Promise<void> return
- Add concurrency and ordering tests for fetch/refresh race scenarios
- Rename local variable from `state` to `entry` in kilo-sessions sync loop
* chore(opencode): remove duplicate imports and fix test layer composition
Remove duplicate `AppRuntime` imports introduced during merge and update
kilo-sessions tests to use Effect-native Auth service instead of static
module calls.
- Remove duplicate `AppRuntime` import in index.ts and instance.ts
- Add Auth.defaultLayer to test layer helper
- Refactor test to yield Auth.Service and use instance methods
- Reorder Effect.provide/Effect.ensuring for correct resource cleanup
* style(opencode): normalize kilocode_change marker comments to block format
Standardize inline `// kilocode_change` annotations across source and
test files to use consistent `// kilocode_change start` / `// kilocode_change end`
block delimiters, improving readability and grep-ability of custom
modifications.
Addresses the two remaining points from @markijbema's review.
Prompt templating now lives in the gateway
-------------------------------------------
The Mercury sentinel-prompt assembly moved out of the VSCode extension
into packages/kilo-gateway/src/edit-prompt.ts. Clients now send
structured editor context (currentFileContent, cursor position,
editable region, recently-viewed snippets, edit-diff history) and the
gateway builds the sentinel-tagged prompt. This keeps the entire
Mercury contract — endpoint, auth, prompt format, response parsing — in
one place that VS Code, JetBrains, and the TUI can all share, instead
of each editor re-implementing the templating.
- New EditBody is the structured context (was: a pre-built `content`
string). Updated the opencode HttpApi schema, the hono zod validator,
both handlers, and regenerated the SDK.
- Deleted the VSCode-side mercuryPromptTemplate.ts (+ spec); the tests
moved to packages/kilo-gateway/test/edit-prompt.test.ts.
- VSCode constants.ts now holds only the editable-region sizing; the
sentinel tokens live in the gateway.
FileIgnoreController
--------------------
NES must not send ignored files (.env, secrets, anything matched by
.gitignore/.kilocodeignore) to the server. The NES provider now:
- skips the request entirely if the active document fails
ignoreController.validateAccess(), and
- filters recently-viewed snippets through the same controller before
they go into the prompt.
It reuses the classic provider's FileIgnoreController instance (now
public) rather than building a second one.
Also: dropped the implicit nextEdit.debug config read in log.ts (debug
is env-only via KILO_NES_DEBUG) so no VSCode autocomplete config is
added — per the "config should move to the backend" guidance.
Validation: typecheck clean across kilo-gateway, opencode, kilo-vscode;
lint clean; gateway 46 tests, vscode next-edit 10 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two-agent review pass on the gateway-routed NES change. Fixes:
Correctness (🔴)
- MercuryEditProvider read the HTTP status off the parsed error body
(`error.status`, always undefined), so 401/402 never reached
onFatalError and NES had no credit-exhausted/auth backoff. Now reads
`response.status` from the SDK result.
- NextEditSuggestionManager applied "insert" suggestions without the
apply-time drift re-validation the "replace" path already had — edits
between the anchor and insertion point could land the insert in the
wrong place. Now re-checks the anchor line before inserting.
- The opencode Effect edit handler collapsed every upstream failure to
HTTP 400; now passes the real status through (mirrors the FIM handler)
so 401/402/429/5xx are distinguishable under the experimental backend.
Conciseness / DRY (🔴)
- Deleted dead module editCompletionParser.ts (+ spec): the gateway
unwraps the fence server-side now, so the VSCode-side parser was unused.
- Hoisted the triplicated extractFencedBody into a single exported
function in kilo-gateway/src/edit.ts; both the hono and Effect handlers
import it. Added a shared EditUpstreamResponse type to replace three
inline copies.
Robustness (🟡)
- extractFencedBody now keeps the body when the closing fence is missing
(truncated/max_tokens output) instead of dropping the suggestion.
- EditHistoryTracker seeds snapshots on document open so the first edit
in a freshly-opened file is captured (was previously dropped).
- Single-line inserts that span non-blank lines below the cursor (a
multi-line→single-line collapse) now route to the decoration path
instead of emitting a ghost item VSCode can't render.
Cleanup (🟡)
- Removed unused constants (MERCURY_EDIT_MODEL_ID, INCEPTION_API_BASE_URL,
INCEPTION_EDIT_PATH).
- getProviderKey typed to DirectAutocompleteProviderID (matches FIM).
- resolveEditTarget keys on kind==="edit" defensively, so a future
FIM-only Inception model can't resolve to the edit endpoint.
- AutocompleteModelDef doc comments made endpoint-neutral (not "FIM").
- Declared the internal accept command in contributes.commands.
Tests
- New packages/kilo-gateway/test/edit.test.ts: resolveEditTarget routing
(incl. the mercury-edit-2 FIM model must NOT reach the edit endpoint)
and extractFencedBody variants (lang tag, sentinels, truncation, blank
lines, no-fence).
- typecheck clean across kilo-gateway, opencode, kilo-vscode; lint clean;
all unit tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Addresses @markijbema's architectural feedback on #10536: moves the HTTP
edit-completion call to the gateway, removes the standalone API-key
setting, and aligns with the provider/model selection design introduced
in #10559.
Wire-level changes
------------------
* New `/kilo/edit` endpoint added to the opencode HttpApi contract
(`packages/opencode/src/kilocode/server/httpapi/groups/kilo-gateway.ts`)
and mirrored into `packages/kilo-gateway/src/server/routes.ts` for the
hono surface. SDK regenerated; `client.kilo.edit({ content, provider,
model, maxTokens })` is now available.
* `packages/kilo-gateway/src/edit.ts` — `EditTarget` resolver mirroring
the FIM pattern. Only the Inception provider is wired today (Mistral
doesn't expose a comparable surface); Kilo Gateway has a placeholder
branch that returns 400 until a server-side proxy exists.
* `packages/kilo-gateway/src/server/edit.ts` — `createEditHandler` reads
the Inception BYOK key from `Auth.get("inception")` and falls back to
`INCEPTION_API_KEY` from env, exactly like the FIM handler.
* The gateway unwraps Mercury's triple-backtick fence (and any
`<|code_to_edit|>` sentinels) server-side so the VSCode response is
just the rewritten code.
* `AutocompleteModelDef` gains an optional `kind: "fim" | "edit"`
discriminator; new entry `inception/mercury-next-edit` (label "Mercury
Next Edit") sets `kind: "edit"` and shares the wire model
`mercury-edit-2`.
VSCode-side
-----------
* `MercuryEditProvider` no longer does its own HTTP — it's now a thin
wrapper around `client.kilo.edit(...)` via `KiloConnectionService`.
* Dropped `kilo-code.new.autocomplete.nextEdit.apiKey` and
`.nextEdit.baseUrl` settings. Auth and routing live in the gateway.
* The `AutocompleteServiceManager` dispatch now switches on the model's
`kind` field (set by `getAutocompleteModel(provider, model)`) instead
of string-comparing a model id, matching Mark's provider+model split.
* The `NextEditInlineCompletionProvider`,
`NextEditSuggestionManager`, prompt template, parser, editable-region
selector, edit-history tracker, recently-viewed-snippets adapter, and
decoration-based jump-to-edit UX remain in the VSCode extension since
they need editor-specific APIs (`InlineCompletionItem`,
`TextEditorDecorationType`, keybinding context keys).
Bot review nits resolved
------------------------
* `INLINE_COMPLETION_ACCEPTED_COMMAND` renamed `kilocode.*` →
`kilo-code.*` to match the project convention.
* `kilo-code.next-edit.acceptOrJump` and `.dismiss` now declared in
`contributes.commands` so VS Code can resolve them in the palette.
* `disposeLog()` wired into `AutocompleteServiceManager.dispose()` so
the dedicated "Kilo Code · Next Edit" OutputChannel doesn't leak.
* Per-keystroke "skip — no API key resolved" log removed (the entire
API-key code path is gone).
Tests
-----
* `bun run check-types:extension` clean
* `bun run lint src` clean
* `bun test src/services/autocomplete/next-edit/__tests__/` — 23/23
pass
Docs
----
* The partner walkthrough at
`packages/kilo-vscode/docs/mercury-next-edit-testing.html` and the
20-test playground under
`packages/kilo-vscode/docs/nes-examples/` survive from the prior
iteration. The walkthrough's "Install the PR locally" section still
applies (the model dropdown choice is now "Mercury Next Edit
(Inception)" — the API-key step is gone since BYOK is plumbed through
the gateway's Auth store).
Known follow-ups (not in this commit)
-------------------------------------
* `FileIgnoreController` plumbing through the NES context builder so
`.env`-style files don't get sent. Hook point identified in
`NextEditInlineCompletionProvider.buildRequestContext`.
* Settings UI changes in the webview to expose Mercury Next Edit as a
selectable provider/model pair alongside the FIM entries.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace `urls: string[]` with provider-specific shapes: kilo and inception
each carry a single `url`, mistral carries no urls (its dual-endpoint
fallback is encapsulated in requestMistralFim). Removes the non-null
assertion on `urls[0]` and the dead "No FIM endpoint configured" branch.
Also tightens `getProviderKey` to take `DirectAutocompleteProviderID`,
which now follows naturally from the narrowed union and prevents the
`DIRECT_FIM_ENV["kilo"]` undefined-lookup footgun.
Previously `getAutocompleteModel` inferred the provider from a bare model
id like "codestral-2508" or "mercury-edit-2" when no provider was set.
That meant a user with a legacy `model` setting could be silently routed
to a direct BYOK provider without an explicit opt-in. Default to Kilo
Gateway whenever provider is unset; direct providers now require an
explicit `provider` setting.
* refactor(opencode): migrate agent promise helpers to kilocode module and adopt Effect-based tests
Remove legacy promise-based helpers (`get`, `list`, `defaultAgent`, `remove`)
from the core agent module and update callsites to use the dedicated
`@/kilocode/agent` module directly. Migrate kilocode-specific tests from
`WithInstance.provide` patterns to the `testEffect` helper with Effect
generators for cleaner, more idiomatic test code.
- Remove `makeRuntime` import and exported promise helpers from agent.ts
- Update HTTP API handlers to import from `@/kilocode/agent` instead of
re-exported `Agent` namespace
- Rewrite agent tests to use `load()` helper or Effect service access
- Convert agent-global-config-dirs and agent-skill-permissions tests to
`testEffect` pattern
- Reorder SDK type definitions (BackgroundProcessLogs/WorkspaceWarpError)
* chore(auth): remove legacy promise helpers and replace with direct Effect service access
Eliminate the exported promise-based convenience functions (`get`, `all`,
`set`, `remove`) from the Auth module and replace all callsites with
explicit `AppRuntime.runPromise` or `makeRuntime` invocations that access
`Auth.Service` directly through Effect's service pattern.
- Delete `makeRuntime`-backed promise helpers from auth/index.ts
- Update CLI entrypoint, kilo-sessions, indexing, and server instance to
use `AppRuntime.runPromise(Auth.Service.use(...))` for auth access
- Inject `Auth.Service` as a dependency into the ModelsDev layer and
consume it via Effect generator instead of promise wrapper
- Create a local `makeRuntime` instance in model-cache.ts for non-Effect
callsites that still need promise-based auth access
- Rewrite tests to manipulate auth.json directly on disk with proper
save/restore semantics instead of relying on removed helpers
* refactor(suggestion): convert suggest tool to Effect-native with injected Command dependency
Transform the suggestion tool from async/promise-based implementation to
idiomatic Effect generators with explicit dependency injection of the
Command service rather than importing and calling module-level helpers.
- Convert `resolvePrompt` from async function to Effect generator that
accepts a `Command.Interface` parameter
- Refactor `SuggestTool` definition to yield `Command.Service` from the
Effect context and thread it through to `resolvePrompt`
- Add `Command.Service` as a dependency to the tool registry layer and
provide `Command.defaultLayer` in both production and test wiring
- Remove unused `makeRuntime` import and exported `get` helper from
command/index.ts
- Add explicit type annotations to Auth delegate in server instance
- Rewrite suggestion tests to use `testEffect` helper with a mock
`Command.Service` layer instead of spying on module exports
* feat(git): migrate WorktreeFamily to Effect service and wire Git.Service as dependency
Convert WorktreeFamily.list from an async function using legacy promise
helpers to an Effect generator that yields Git.Service from context,
eliminating the need for the removed `run` promise wrapper in git/index.
- Replace `WorktreeFamily.list()` async function with Effect.fn generator
that obtains Git.Service and InstanceState from the Effect context
- Remove legacy `makeRuntime`/`run`/`runPromise` exports from git module
- Update RecallTool to thread Git.Service through to WorktreeFamily calls
via EffectBridge
- Add Git.Service as a required dependency in tool registry and HTTP
server route layers
- Update all test layers to provide Git.defaultLayer
* chore(mcp): replace legacy promise helpers with Effect-native AppRuntime calls
Remove exported promise-based `status`, `connect`, and `disconnect`
helpers from MCP module and convert the network recovery callsite in
SessionNetwork to use AppRuntime.runPromise with Effect.gen directly.
* refactor(auth): adopt makeRuntime helper for Auth service resolution in kilo modules
Replace AppRuntime.runPromise with locally scoped makeRuntime instances
in kilo-sessions and kilocode/indexing modules, removing the dependency
on the global AppRuntime singleton for Auth service access.
* fix(test): simplify cleanup error handling in provider test
Replace try-catch block with promise .catch() for file unlink operation
during test teardown.
On a fresh CI runner, multiple Turbo tasks starting in parallel can race
to extract the Gradle wrapper zip, producing ClosedFileSystemException.
Run ./gradlew --version before turbo test:ci to ensure the wrapper is
fully extracted before any parallel task touches it.
Add the JetBrains frontend migration wizard for the legacy migration core. The wizard renders as a MODAL_LAYER blocking overlay inside every visible SessionUi and is driven by a shared KiloMigrationService app service.
- Shared: MigrationDto.kt with full DTO set, KiloMigrationRpcApi with status/detect/migrate/skip/finalize/cleanup
- Backend: KiloBackendLegacyMigrationStoreService (PropertiesComponent status persistence), MigrationRpcMapper (pure bidirectional mapper), KiloMigrationRpcApiImpl (channelFlow streaming off Dispatchers.IO), KiloMigrationRpcApiProvider; extend KiloBackendMigrationManager with status/mark
- Frontend service: KiloMigrationService with idempotent check, in-flight guard, progress collection from streamed events, skip/finish/force re-import; MigrationSelectionBuilder mirrors VS Code preselection rules
- SessionRootPanel: new Blocker class at MODAL_LAYER with setBlocker/setBlocked helpers; existing scroll overlay at PALETTE_LAYER unchanged
- Swing wizard: MigrationWizardPanel (What's New + Migrate screens, retained component tree), MigrationItemRow, MigrationStatusIcon, SessionMigrationProgressPanel, SessionMigrationSummaryPanel, MigrationOverlayPanel
- SessionUi: wired to MigrationUiController via coroutine state collection on Dispatchers.Main; check() called from addNotify() and AppChanged READY
- Tests: SessionRootPanelTest, SessionUiLayoutTest, KiloMigrationServiceTest, SessionUiMigrationTest, FakeMigrationRpcApi, FakeMigrationUiController
Use session.configModel() instead of session.selected() in NewWorktreeDialog
so the overridden comparison (line 124) and the reset handler (line 444) both
use the config-based model. This prevents stale overridden states from
session.selected() from leaking into the worktree dialog's override detection
and reset behaviour.
Partially fixes#9349.
Both the copy and export handlers now pass `{ throwOnError: true }` to
`sdk.client.session.messages()` and drop the `?? []` fallback, so a failed
fetch (404/400/network) throws into the existing catch block and surfaces an
error toast instead of silently writing/returning an empty transcript.
- Add test:ci root script as alias for bun turbo test:ci
- Wire typecheck as a dependency of kilo-jetbrains#test:ci in turbo.json so compile runs before tests
- Exit with Gradle's code on Linux/macOS so failures block the repo-wide turbo test:ci run; Windows stays non-blocking due to inherent IntelliJ test flakiness there
Remove accidentally committed Gradle build cache files from the
JetBrains package, add the .gradle directory to .gitignore, and
update user-facing strings from "opencode.json" to "kilo.json".
Expand extractFilePathFromHref test coverage to handle file:// URLs on
Unix, Windows drives, and encoded characters. Previously file:// URLs
were expected to return undefined; now they resolve to local paths.
Exclude @kilocode/kilo-jetbrains from turbo typecheck filter to avoid
build errors in that package.
Use providerID variable instead of provider.id in dialog-provider to
fix incorrect property access after destructuring. Update cancel method
in TaskPromptOps stubs to return Effect.void matching the expected
interface. Remove obsolete workspace-restore test file and add missing
fixture import.
Reformat multiline arrays, JSX props, CSS transitions, and test
indentation to comply with the project's prettier configuration.
Also reorder auto-generated SDK type imports alphabetically and
relocate type definitions to match updated openapi.json output.
Port VS Code v5 migration logic to JetBrains backend: provider mapping,
MCP/custom-mode/settings conversion, session parser with deterministic SHA-1
IDs, HTTP backend adapter, and LegacyMigrationEngine orchestration. No UI,
no EDT dependencies — callers own threading and sequencing. 72 tests passing.
Track child session IDs discovered from task tool part metadata and subscribe
to their permission events so subagent permission prompts surface in the root
session UI instead of hanging silently. Also makes runtime auto-approve
non-persistent (no longer writes PropertiesComponent).
Move parseProviders, parseCommands, and parsePathState out of
KiloBackendWorkspace and KiloBackendModelStateManager into
KiloCliDataParser so no caller directly navigates JSON.
parseCommands intentionally ignores the template field, fixing
JetBrains startup when lazy CLI command templates serialize as {}.
Reorganize KiloCliDataParserTest into three @Nested groups
(SseEvents, HttpResponses, RequestBuilders) and add unit coverage
for all three new parser methods.
- retryPrompt() now uses msg.info.providerID/modelID instead of
model.model so login-resume preserves the original message's model
- Add AccountOverlayChanged to expected events in HistoryLoadingTest,
ListenerLifecycleTest, and WorkspaceWatchingTest (replay now always
fires the initial acctState on addListener)
- Update SessionUiLayoutTest overlay tests to set a logged-in profile
since the overlay is now hidden when not logged in
- Expose appRpc in SessionUiTestBase so subclasses can mutate app state
Re-enable @kilocode/kilo-jetbrains in bun turbo typecheck (package.json) and
bun turbo test:ci (test.yml). Add Java 21 setup to the typecheck workflow so
Gradle can run. Fix three serialization test failures:
- KiloProfile200Response with null balance / with organizations: Effect's HttpApi
OpenAPI generator emits balance and currentOrgId as non-nullable even though
the server schema uses Schema.NullOr. Add fixProfileNullable step to
OpenApiSpecNormalizer that wraps these fields in anyOf: [{schema}, {type:null}]
before Kotlin client generation, plus regression tests.
- model limit context and output deserialize with large values (NoSuchMethodError):
compileTestKotlin was not invalidated when the generated API type changed, leaving
stale bytecode referencing the old ProviderConfigModelsValueAnyOfLimit class.
Wire compileTestKotlin -> fixGeneratedApi in backend/build.gradle.kts so API
regeneration always invalidates test compilation.
Move subagent navigation into the existing palette: a
"View subagents" command entry, a dedicated picker panel, and a
Down-arrow shortcut from the empty composer.
Strip operation-level tags from the normalized spec so all routes land
in a single DefaultApi class (required by backend sources). Remove
dot-notation duplicate schemas (Event.tui.command.execute etc.) and
rewrite their refs to camelCase equivalents to fix duplicate file path
collisions. Deduplicate root-level tags array to pass spec validation.
Remove NormalizeOpenApiSpecConfig.kt; pty-specific dedup rules are no
longer needed since tags are stripped from operations entirely.
Add BaseSessionQuestionPanel in session/ui/shared as a shared rounded card shell for QuestionView and LoginRequiredView. The panel provides a consistent surface/outline, header and description text areas with editor-font styling, an optional top slot for navigation, and body/footer slots for view-specific content.
* fix(jetbrains): normalize duplicate PTY OpenAPI tag
* refactor(jetbrains): extract OpenAPI spec normalization into dedicated package
Move NormalizeOpenApiSpecTask into a `normalization` package and split
configuration (duplicate tag names, final tag mappings, operation id
routing) into a separate NormalizeOpenApiSpecConfig file.
The task now handles arbitrary duplicate tags via config-driven rules
and rewrites both tag metadata and path operation tags, replacing the
previous single-purpose pty-only implementation.
* feat(jetbrains): add OpenApiSpecNormalizer with unit tests and decouple logic from Gradle task
Introduce OpenApiSpecNormalizer as a pure-function object that owns all
JSON parsing, tag deduplication, and path rewriting logic. The Gradle
task now delegates to this normalizer, keeping task wiring minimal.
Add JUnit 5 test infrastructure to the build-tasks module and cover the
normalizer with tests for successful renames, no-op passthrough, and
missing-operation error handling. Replace Array usages in config data
classes with List for idiomatic Kotlin collections.
* chore: generate
* sync release versions for v1.14.33
* refactor(cli): convert pr command to effectCmd (#25465)
* chore: generate
* refactor(cli): convert export command to effectCmd (#25471)
* refactor(cli): convert plugin command to effectCmd (#25473)
* refactor(cli): convert import command to effectCmd (#25467)
* refactor(cli): convert stats command to effectCmd (#25474)
* chore: generate
* refactor(cli): convert session subcommands to effectCmd (#25483)
* feat: refactor bash tool with shell-aware prompts for bash, pwsh+powershell, and cmd (#20039)
* refactor(cli): convert debug agent command to effectCmd (#25485)
* chore: generate
* refactor(cli): convert debug subcommands to effectCmd (#25479)
* chore: generate
* fix(instance): run bootstrap from instance store (#25475)
* chore: generate
* feat(cli): auto-dispose InstanceContext after effectCmd handlers (#25481)
* docs: clarify LSP and formatter opt-in config (#25502)
* chore: generate
* test(httpapi): add route exerciser
* chore: generate
* Normalize instance lifecycle wiring (#25501)
* chore: generate
* refactor(cli): drop redundant explicit Effect.ensuring(store.dispose) (#25503)
* chore: generate
* feat: default HTTP API backend to on for dev/beta channels
* feat(cli): add instance: false opt-out to effectCmd (#25507)
* refactor(cli): convert web + account to effectCmd (instance: false) (#25512)
* Refactor v2 session events as schemas (#24512)
* chore: generate
* refactor(lifecycle): bootstrap as pure orchestration (#25510)
* feat(cli): allow effectCmd instance to be a function of args (#25517)
* refactor(cli): convert debug wait, agent list, acp to effectCmd (#25518)
* refactor(cli): convert run command to effectCmd (#25519)
* chore: generate
* refactor(acp): drop async from synchronous ACP.init (#25520)
* chore: rm log statement (#25470)
* fix(desktop): limit zoom handler to zoom keys (#25516)
* chore(opencode): exclude .map files from CLI binary build (#25500)
* refactor(cli): convert github subcommands to effectCmd (#25522)
* chore: generate
* refactor(cli): convert mcp list, auth, auth list, logout to effectCmd (#25521)
* chore: generate
* chore: bump Effect beta (#25524)
* refactor(cli/stats): Stage 4 — fully Effect-native body (#25523)
* fix(httpapi): pagination Link header echoes request host (#25527)
* refactor(cli): convert agent / providers / mcp to effectCmd (#25525)
* chore: generate
* fix(session): encode v2 session responses (#25528)
* chore: update nix node_modules hashes
* fix: regression w/ auth login where stderr was ignored instead of inherited (#25529)
* refactor(cli/mcp+agent): Stage 4 — drop AppRuntime.runPromise bridges (#25530)
* refactor(cli/providers): Stage 4 — drop inline AppRuntime.runPromise calls (#25532)
* fix(cli): bridge Instance.current ALS in effectCmd handlers (regression from #25522) (#25546)
* Add debug info command (#25550)
* ci
* core: update triage agent to use qwen3.6-plus model for improved response quality
* core: simplify triage workflow to focus on issue ownership
Switch triage agent to gpt-5.4-nano for faster issue assignment. Remove label
management from the triage tool so it only assigns owners based on team
ownership rules. This reduces noise in the issue tracker and ensures issues
get to the right team member immediately without unnecessary labels.
Update team structures to reflect current ownership and add script for
processing unassigned issues.
* chore: generate
* ci: remove automatic labels from GitHub issue templates to allow manual triage
* ci: remove vouch-based contributor filtering workflows
Removes the automated vouch system that filtered issues and PRs from non-vouched users. This simplifies the contribution process by removing the requirement for maintainers to manually vouch contributors before they can participate.
* ci: stop sending daily community recap notifications
* ignore: remove triage-unassigned.ts script
This script was used to batch-triage open GitHub issues without assignees.
Removing as the triage workflow has evolved and this batch approach is no longer needed.
* fix(vcs): avoid unbounded diff memory usage (#25581)
* refactor(server): extract Hono-coupled utilities to backend-neutral modules (#25542)
* chore: generate
* feat(server): Server.openapi() backed by HttpApi spec, parity-checked against Hono output (#25545)
* chore: generate
* feat(server): native HttpApi listener with Bun.serve + WS upgrade (#25547)
* fix(acp): pass server auth to internal client (#25591)
* fix(sdk+cli): surface real errors instead of bare {} when server returns empty body (#25592)
* chore: generate
* fix(httpapi): add basic auth challenge for browser login
Adds a WWW-Authenticate challenge for unauthorized experimental HttpApi UI fallback responses so browsers open the Basic Auth prompt when a server password is configured.
* chore: generate
* ci: only build electron desktop (#19067)
* feat: group changelog bugfixes (#25597)
* fix(auth): respect server username in clients (#25596)
* refactor(config+core): drop ConfigPaths.readFile, add AppFileSystem.readFileStringSafe, flatten TuiConfig.loadState (#25602)
* chore: generate
* refactor(cli/github+run): Stage 4 — drop AppRuntime.runPromise bridges (#25539)
* refactor(cli/providers): flatten — Effect-native handlers end-to-end (#25537)
* chore: generate
* fix(auth): add username option for basic auth in RunCommand (#25600)
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
* fix(server): support desktop PTY websockets with HttpApi (#25598)
* chore: generate
* Add v2 session failure events (#25628)
* chore: generate
* fix(server): serve embedded UI from bunfs (#25632)
* chore: generate
* refactor(cli): effectify provider commands (#25633)
* fix(app): preserve auth token credentials (#25636)
* Effectify plugin agent regression test (#25646)
* fix: allow Codex Spark with Codex OAuth (#25640)
* feat(server): pty websocket auth tickets (#25660)
* chore: generate
* fix(app): prevent terminal recovery loops (#25710)
* chore: generate
* fix(opencode): strip transfer-encoding in UI proxy and allow public manifest assets (#25698)
Co-authored-by: Kit Langton <kit.langton@gmail.com>
* test(server): regression reproducers for #25698 (#25714)
* chore: generate
* fix: ensure anthropic sdk properly resolves when using azure (#25721)
* sync
* chore(docs): rename firmware provider to frogbot (#25453)
* fix(worktree): fork workspace worktree boot (#25723)
* fix(server): provide fresh ConfigProvider per HttpApi listener (#25726)
* test(agent): skip InstanceBootstrap in plugin-agent regression test (#25737)
* sync
* fix: ensure effect server middleware properly parses errors (#25717)
* release: v1.14.34
* refactor: kilo compat for v1.14.34
* feat(kilocode): migrate kilo HTTP routes to Effect HttpApi layer
Introduce a structured Effect HttpApi surface for all Kilo-specific
endpoints, replacing inline Hono handler logic with declarative group
definitions, typed schemas, and composable handler layers.
Key changes:
- Add HttpApi group and handler modules for commit-message, enhance-prompt,
indexing, kilocode, network, remote, session-import, suggestion, and
telemetry
- Extract allow-everything permission logic into a reusable Effect function
- Register all Kilo HttpApi groups in InstanceHttpApi and wire route
forwarding in the Hono instance router
- Export Suggestion.RequestSchema and annotate schemas with identifiers
- Use NonNegativeInt for indexing status fields and Schema.Finite for
network wait timestamps
- Add httpapi-bridge test asserting parity between Hono and Effect specs
for all 22 Kilo overlay routes
- Regenerate SDK types and openapi.json to reflect the new endpoints
* style: apply formatting and lint fixes across packages
Reformat code with consistent line breaks, trailing commas, semicolons,
and line-length compliance. No logic changes — purely whitespace,
indentation, and punctuation adjustments driven by the project formatter.
- Break long function signatures and conditionals across multiple lines
- Remove trailing blank lines and stray leading newlines
- Replace string-expression JSX whitespace with literal spaces
- Convert quoted object keys to unquoted where valid
- Remove erroneous shell command prefix from openapi.json
- Deduplicate SessionNetworkWait1 schema and simplify Finite unions to
plain number type in OpenAPI spec
* feat(kilo-gateway): add Effect HttpApi endpoints for kilo gateway operations
Extract shared handler logic from Hono routes into reusable functions in
kilo-gateway/server/handlers.ts and wire up new Effect HttpApi endpoints
for profile, notifications, organization switching, claw status, and
claw chat credentials.
- Add handlers.ts with pure business logic (getProfile, getNotifications,
setOrganization, getClawStatus, getClawChatCredentials)
- Define KiloGatewayApi group with typed schemas for all endpoints
- Implement Effect-based handler layer in httpapi/handlers/kilo-gateway.ts
- Register kilo gateway routes in instance router and HttpApi composition
- Add config/warnings endpoint to config group and handler
- Regenerate SDK types and client methods for new endpoints
- Update OpenAPI spec with /kilo/* and /config/warnings paths
- Export new constants (KILO_CHAT_URL, KILO_EVENT_SERVICE_URL) and
handler utilities from kilo-gateway package index
* refactor(kilo-gateway): extract cloud sessions logic and wire up cloud sync endpoints
Move inline cloud-sessions fetch logic from Hono route handler into a
reusable getCloudSessions function in handlers.ts, and introduce new
Effect HttpApi endpoints for fetching and importing individual cloud
sessions.
- Extract getCloudSessions handler from routes.ts inline implementation
- Export fetchCloudSession, fetchCloudSessionForImport, importSessionToDb
from kilo-gateway package
- Add cloudSession (GET /kilo/cloud/session/:id) endpoint for previewing
remote session data
- Add cloudSessionImport (POST /kilo/cloud/session/import) endpoint to
download and persist cloud sessions locally
- Define CloudSession, CloudSessionData, CloudMessage schemas in the
kilo-gateway API group
- Change claw status error response from 500 InternalServerError to
503 ServiceUnavailable
- Register new cloud routes in instance router
- Add test coverage for route disambiguation between import and :id paths
- Regenerate SDK types and OpenAPI spec
* feat(kilocode): add worktree diff, FIM proxy, audio transcription, and session viewed endpoints
Introduce several new Effect HttpApi endpoints across the kilo-gateway
and experimental API groups to support agent manager workflows and
enhanced gateway proxying.
- Add worktree diff endpoints (diff, diff/summary, diff/file) for
comparing worktree changes against a base branch
- Add FIM completion proxy endpoint with streaming SSE response and
timeout handling
- Add audio transcriptions proxy endpoint forwarding to Kilo Gateway
- Add organization modes endpoint to fetch custom modes config
- Add session/viewed endpoint to track which sessions the user has open
- Extend session list query with projectID and worktrees parameters
- Register all new routes in Hono instance router
- Regenerate SDK types and OpenAPI spec
* refactor(kilo-gateway): clean up proxy auth naming, error handling, and OpenAPI schema alignment
Rename `proxy` helper to `proxyAuth` for clarity, switch modes endpoint
to gracefully handle missing auth instead of returning BadRequest, remove
redundant Content-Type header from audio transcriptions response, and
fix OpenAPI parameter types:
- Change `worktrees` query param from string enum to boolean
- Add `^que.*` pattern to network endpoint requestID path params
- Register experimental session worktrees in query parameter schemas
- Re-enable and update Effect HttpApi route parity tests
* fix(opencode): migrate Instance.provide calls to WithInstance.provide
Replace direct `Instance.provide` usage with `WithInstance.provide` across
source modules and test files to decouple runtime context provisioning
from the core Instance singleton.
- Update kilo-sessions, remote-sender, roll-call, and plan-followup source
- Remove unused `Instance` imports where only `WithInstance` is needed
- Drop unnecessary `init` param from indexing-worktree test calls
- Add missing `WithInstance` import in fixture-dependent test files
* refactor(opencode): extract indexing event schema and align OpenAPI contracts
Move the IndexingStatus Effect schema out of the KiloIndexing namespace into
a dedicated `indexing-event.ts` module so it can be shared between the bus
event system and the HttpApi layer without circular imports.
Additionally fix several OpenAPI spec inconsistencies:
- Inline PermissionReplyBody into the endpoint payload schema
- Make `organizationId` nullable in the organization set endpoint
- Replace opaque string response for `/kilo/fim` with a structured
streaming completion schema
- Register `indexing.status` as a typed SSE event in the global event union
- Add `matchLegacyKiloOpenApi` post-processor for backward-compatible
nullable fields and FIM response shape
- Relocate Kilo-specific bridge tests to `test/kilocode/server/` and trim
duplicated assertions from the core bridge test file
* feat(opencode): rename InstanceStore to InstanceRuntime and refine model schema
Rename the `InstanceStore` module to `InstanceRuntime` across all consumer
sites to better reflect its role as a runtime lifecycle manager rather than
a persistence layer. Update the kilo-gateway route dependency key from
`InstanceStore` to `Instances` for clarity.
Additional changes:
- Replace `Schema.Number` with `Schema.Finite` for `recommendedIndex` in
both the provider and models schemas
- Inject `InstanceStore.Service` into the ProviderAuth layer and use its
`disposeAll()` method instead of escaping to a raw promise
- Remove obsolete `getBootstrapRunEffect` usage from indexing startup tests
- Add missing `warnings` method to the test config fixture
* refactor(kilocode): decouple provider-auth lifecycle, add cloud-fork CLI option, and migrate indexing config to Effect Schema
Extract `disposeAllInstancesAfterProviderAuthCallback` into a dedicated
module and invoke it from the provider OAuth callback handler instead of
coupling it to the ProviderAuth layer. This removes the InstanceStore
dependency from `ProviderAuth.layer`.
Additional changes:
- Add `--cloud-fork` CLI option to the run command for fetching sessions
from cloud and continuing locally
- Replace the Zod-bridged `Schema.Any` indexing config with a native
Effect `IndexingSchema` definition in kilo-indexing, propagating typed
config through the SDK OpenAPI spec
- Use `optionalOmitUndefined` for `recommendedIndex` to emit clean JSON
- Fix `request.source.signal` access by guarding with `instanceof Request`
- Replace `Effect.catchAllCause` with `Effect.catchCause` in telemetry
- Migrate tests from `BashTool` to `ShellTool`, extract `TestConfig`
fixture, and convert stats-subagent-cost tests to use `testEffect`
- Reorder SDK event union members to match updated OpenAPI schema
- Export `aggregateSessionStats` for Kilo regression test coverage
- Widen `setViewedSessions` input to accept readonly arrays
* feat(kilocode): introduce EffectBridge for async-to-effect interop and lazify runtime constructors
Replace raw `Effect.promise` calls across HTTP API handlers with
`EffectBridge.fromPromise` / `EffectBridge.make` to ensure proper error
propagation and context forwarding when bridging imperative async code
into the Effect runtime.
Wrap top-level `makeRuntime` calls in `plan-followup.ts` with `lazy()`
to defer service instantiation until first access, avoiding eager
initialization side-effects during module loading.
Also reorder SDK event union members and type definitions to reflect
updated OpenAPI schema generation output.
* refactor(kilo-sessions): lazify WithInstance and InstanceRuntime imports to break circular module dependencies
Convert static imports of WithInstance and InstanceRuntime to dynamic
imports across kilo-sessions, remote-sender, agent, and plan-followup
modules. This eliminates module initialization cycles that caused
undefined references during test execution (e.g. Worktree → bootstrap →
kilo-sessions → remote-sender → app-runtime → Worktree).
Each call site now uses an async `provide()` helper or inline dynamic
`import()` to defer resolution until runtime, preserving the same
behavioral semantics while decoupling the static dependency graph.
* fix(test): replace Instance.provide with WithInstance.provide in network tests
Update session network test to use the correct WithInstance.provide API,
aligning with the refactored import structure introduced in the circular
dependency fix.
* refactor(session): use Schema.Finite for network restored time and deduplicate event type
Replace Schema.Number with Schema.Finite to enforce finite numeric
values for the time field in session network restored events. Remove
the duplicate EventSessionNetworkRestored1 type from the OpenAPI spec
and SDK, consolidating on a single EventSessionNetworkRestored with a
plain number type instead of the anyOf union with NaN/Infinity strings.
* refactor(remote): simplify effect bridge usage in enable handler
Replace `EffectBridge.make()` and `bridge.promise()` pattern with
direct `Effect.runPromise(EffectBridge.fromPromise(...))` call,
removing the unnecessary intermediate bridge instance.
* refactor(repo): rebrand to kilo and improve issue triage configuration
Replace legacy "opencode" references with "kilo" in CLI output,
API metadata, SDK error messages, and documentation. Add automatic
labels to GitHub issue templates, expand triage agent with jetbrains
and extension teams, and update the github-triage tool to target the
Kilo-Org/kilocode repository.
* fix(opencode): resolve race conditions and update tests for kilo compatibility
Remove eager publish call in indexing initialization that caused
premature event emission. Add foreign key constraint tolerance in
next-message projector to handle writes racing against deleted
sessions. Fix test environment isolation for gateway headers and
permission tests, update auth test assertions to use "kilo" username,
and remove stale indexing route from httpapi-bridge expectations.
* fix(opencode): replace InstanceLayer.layer with explicit dependencies in instance context test
Avoid InstanceLayer.layer's lazy bootstrap import in the test graph by
directly providing InstanceStore.defaultLayer with InstanceBootstrap.defaultLayer,
preventing unintended side effects during test execution.
* test(opencode): increase timeout for flaky plugin lifecycle CI test
Bump dispose resolution timeout from 7s to 15s to reduce flakiness
in CI environments where resource cleanup may take longer.
---------
Co-authored-by: opencode-agent[bot] <opencode-agent[bot]@users.noreply.github.com>
Co-authored-by: opencode <opencode@sst.dev>
Co-authored-by: Kit Langton <kit.langton@gmail.com>
Co-authored-by: Luke Parker <10430890+Hona@users.noreply.github.com>
Co-authored-by: Dax <mail@thdxr.com>
Co-authored-by: Aiden Cline <63023139+rekram1-node@users.noreply.github.com>
Co-authored-by: Youssef Achy <19510452+PanAchy@users.noreply.github.com>
Co-authored-by: Dax Raad <d@ironbay.co>
Co-authored-by: Shoubhit Dash <shoubhit2005@gmail.com>
Co-authored-by: OpeOginni <107570612+OpeOginni@users.noreply.github.com>
Co-authored-by: Brendan Allan <14191578+Brendonovich@users.noreply.github.com>
Co-authored-by: Utkub24 <76127062+Utkub24@users.noreply.github.com>
Co-authored-by: Frank <frank@anoma.ly>
Co-authored-by: Colby Gilbert <colby@firmware.ai>
Avoid InstanceLayer.layer's lazy bootstrap import in the test graph by
directly providing InstanceStore.defaultLayer with InstanceBootstrap.defaultLayer,
preventing unintended side effects during test execution.
Remove eager publish call in indexing initialization that caused
premature event emission. Add foreign key constraint tolerance in
next-message projector to handle writes racing against deleted
sessions. Fix test environment isolation for gateway headers and
permission tests, update auth test assertions to use "kilo" username,
and remove stale indexing route from httpapi-bridge expectations.
Replace legacy "opencode" references with "kilo" in CLI output,
API metadata, SDK error messages, and documentation. Add automatic
labels to GitHub issue templates, expand triage agent with jetbrains
and extension teams, and update the github-triage tool to target the
Kilo-Org/kilocode repository.
Replace `EffectBridge.make()` and `bridge.promise()` pattern with
direct `Effect.runPromise(EffectBridge.fromPromise(...))` call,
removing the unnecessary intermediate bridge instance.
The export options dialog checkbox rows only set visual focus on mouse click but don't toggle the checkbox state. Update onMouseUp handlers to both set focus and toggle the corresponding boolean value.
When a session hit a PAID_MODEL_AUTH_REQUIRED (401) error, the login-resume
prompt was sent with null providerID/modelID because user messages never carry
those fields. This caused the backend to use its default model instead of the
originally selected one, resulting in silent sub-agent activity that appeared
as a UI hang. retryPrompt() now uses model.model parsed via parseModel(), the
same approach as promptDto().
Fixes#10396
Generated OpenAPI client churn (#10395) breaks the JetBrains gradle
typecheck. Exclude @kilocode/kilo-jetbrains from the root `bun typecheck`
filter so contributors and the typecheck CI workflow don't need Java/Gradle.
The jetbrains test:ci pipeline still runs the gradle typecheck via Turbo's
task graph, so the plugin remains covered in its own CI job.
Replace Schema.Number with Schema.Finite to enforce finite numeric
values for the time field in session network restored events. Remove
the duplicate EventSessionNetworkRestored1 type from the OpenAPI spec
and SDK, consolidating on a single EventSessionNetworkRestored with a
plain number type instead of the anyOf union with NaN/Infinity strings.
Update session network test to use the correct WithInstance.provide API,
aligning with the refactored import structure introduced in the circular
dependency fix.
PR #10274 added useProvider() and useConfig() calls inside FullScreenDiffView
to power speech-to-text in inline review comments. Both hooks throw when called
outside their respective provider contexts.
DiffViewerApp.tsx (the Changes panel) only wrapped content in VSCodeProvider and
ServerProvider, so rendering FullScreenDiffView there crashed the component tree
and left the panel empty.
Fixes the empty Changes panel by wrapping DiffViewerShell in the missing
ProviderProvider and ConfigProvider.
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Convert static imports of WithInstance and InstanceRuntime to dynamic
imports across kilo-sessions, remote-sender, agent, and plan-followup
modules. This eliminates module initialization cycles that caused
undefined references during test execution (e.g. Worktree → bootstrap →
kilo-sessions → remote-sender → app-runtime → Worktree).
Each call site now uses an async `provide()` helper or inline dynamic
`import()` to defer resolution until runtime, preserving the same
behavioral semantics while decoupling the static dependency graph.
Replace raw `Effect.promise` calls across HTTP API handlers with
`EffectBridge.fromPromise` / `EffectBridge.make` to ensure proper error
propagation and context forwarding when bridging imperative async code
into the Effect runtime.
Wrap top-level `makeRuntime` calls in `plan-followup.ts` with `lazy()`
to defer service instantiation until first access, avoiding eager
initialization side-effects during module loading.
Also reorder SDK event union members and type definitions to reflect
updated OpenAPI schema generation output.
* docs: update KiloClaw pricing post-beta
* docs: simplify KiloClaw pricing, link to app for current plans
* chore: add changeset for KiloClaw pricing update
Extract `disposeAllInstancesAfterProviderAuthCallback` into a dedicated
module and invoke it from the provider OAuth callback handler instead of
coupling it to the ProviderAuth layer. This removes the InstanceStore
dependency from `ProviderAuth.layer`.
Additional changes:
- Add `--cloud-fork` CLI option to the run command for fetching sessions
from cloud and continuing locally
- Replace the Zod-bridged `Schema.Any` indexing config with a native
Effect `IndexingSchema` definition in kilo-indexing, propagating typed
config through the SDK OpenAPI spec
- Use `optionalOmitUndefined` for `recommendedIndex` to emit clean JSON
- Fix `request.source.signal` access by guarding with `instanceof Request`
- Replace `Effect.catchAllCause` with `Effect.catchCause` in telemetry
- Migrate tests from `BashTool` to `ShellTool`, extract `TestConfig`
fixture, and convert stats-subagent-cost tests to use `testEffect`
- Reorder SDK event union members to match updated OpenAPI schema
- Export `aggregateSessionStats` for Kilo regression test coverage
- Widen `setViewedSessions` input to accept readonly arrays
Click any section header (Favorites, Recommended, or a provider) to
collapse it and skip an entire provider with one click. Search ignores
collapse state. Collapse state resets each time the picker opens.
Rename the `InstanceStore` module to `InstanceRuntime` across all consumer
sites to better reflect its role as a runtime lifecycle manager rather than
a persistence layer. Update the kilo-gateway route dependency key from
`InstanceStore` to `Instances` for clarity.
Additional changes:
- Replace `Schema.Number` with `Schema.Finite` for `recommendedIndex` in
both the provider and models schemas
- Inject `InstanceStore.Service` into the ProviderAuth layer and use its
`disposeAll()` method instead of escaping to a raw promise
- Remove obsolete `getBootstrapRunEffect` usage from indexing startup tests
- Add missing `warnings` method to the test config fixture
Move the IndexingStatus Effect schema out of the KiloIndexing namespace into
a dedicated `indexing-event.ts` module so it can be shared between the bus
event system and the HttpApi layer without circular imports.
Additionally fix several OpenAPI spec inconsistencies:
- Inline PermissionReplyBody into the endpoint payload schema
- Make `organizationId` nullable in the organization set endpoint
- Replace opaque string response for `/kilo/fim` with a structured
streaming completion schema
- Register `indexing.status` as a typed SSE event in the global event union
- Add `matchLegacyKiloOpenApi` post-processor for backward-compatible
nullable fields and FIM response shape
- Relocate Kilo-specific bridge tests to `test/kilocode/server/` and trim
duplicated assertions from the core bridge test file
Add UiStyle.Fonts tokens (display, heading, large) backed by JBFont
helpers that scale with the platform default font. Replace ad hoc
deriveFont(Font.BOLD, size * multiplier) calls in LoggedOutProfileUi
and the direct JBFont.h1().asBold() call in LoggedInProfileUi with the
new shared tokens.
Fix UiStyle.Colors.cardBg() which was hardcoded to Color.WHITE/BLACK,
breaking custom themes. Now uses JBColor.lazy resolving TextField.background
to follow the active theme's input surface color.
Multi-question prompts now show a Review pseudo-step before submitting,
listing all questions and selected answers (matching VS Code behavior).
Completed question tool parts render as a structured 'Questions / N answered'
card instead of raw output text.
When a linked question request is active, suppress the matching pending/running
question tool card from the assistant message transcript. Completed tool results
remain visible. Matches VS Code behavior where the tool part is not rendered as
a normal tool card while the question form is shown.
Replace Kotlin UI DSL with bare Swing in LoggedOutProfileUi. Introduce
LoginState sealed interface with attempt-based cancellation to discard
stale completions after cancel. Add ZXing QR code generation from the
verification URL. New auth card shows title, URL row with copy/browse,
QR image, spaced device code, countdown timer (M:SS), and cancel.
Login errors compact HTML payloads and offer Try Again. Backend and
frontend tests cover auth mapping, QR generation, pending UI, cancel
invalidation, and error retry.
Convert the first provider env/config/filtering tests to Effect-aware instance fixtures while keeping behavior unchanged and documenting neutral timing.
Replace direct `Instance.provide` usage with `WithInstance.provide` across
source modules and test files to decouple runtime context provisioning
from the core Instance singleton.
- Update kilo-sessions, remote-sender, roll-call, and plan-followup source
- Remove unused `Instance` imports where only `WithInstance` is needed
- Drop unnecessary `init` param from indexing-worktree test calls
- Add missing `WithInstance` import in fixture-dependent test files
Reduce avoidable setup costs in slow opencode tests while preserving reviewed coverage and recording the benchmark evidence for follow-up test-suite work.
Refactor QuestionView from a flat all-at-once layout to a carousel that
shows one question per screen, matching the VS Code question dock pattern:
- Shows 'X of Y questions' summary in the card header
- Back/forward HoverIcon nav buttons in the header; forward disabled until
the current question has an answer
- Single-select items render as JBRadioButton rows (bold label + description)
- Multi-select items render as JBCheckBox rows
- Footer: Dismiss on the left; Next (middle questions) or Submit (last)
- Selections survive back/forward navigation
- Tests updated: radio/checkbox discovery, navigation, back/selection
preservation, and disabled-next guard
- Adds 'new file' marker to check-forbidden-strings workflow
- Marks the SKIP_FILES addition in extract-source-links.ts
- Updates nvidia-headers test to assert the new kilo.ai/Kilo Code values
Introduce several new Effect HttpApi endpoints across the kilo-gateway
and experimental API groups to support agent manager workflows and
enhanced gateway proxying.
- Add worktree diff endpoints (diff, diff/summary, diff/file) for
comparing worktree changes against a base branch
- Add FIM completion proxy endpoint with streaming SSE response and
timeout handling
- Add audio transcriptions proxy endpoint forwarding to Kilo Gateway
- Add organization modes endpoint to fetch custom modes config
- Add session/viewed endpoint to track which sessions the user has open
- Extend session list query with projectID and worktrees parameters
- Register all new routes in Hono instance router
- Regenerate SDK types and OpenAPI spec
The forbidden-string list contains opencode.ai URLs as literal patterns
to ban; they aren't real source links and shouldn't show up in the
source-links manifest.
Adds commented-out entries for the URLs/strings we want to ban once the
underlying call sites are rebranded, and tells the upstream-merge agent
to flag new upstream-attribution leaks for inclusion in the list.
Replaces hardcoded opencode.ai/anomalyco URLs in production code paths:
LLM provider HTTP-Referer/X-Title attribution headers, the TUI error
dialog's bug-report URL, and the github-remote parser test fixtures.
Extends check-forbidden-strings with patterns for these leaks (with a
narrow allowlist for fork-lineage docs and upstream-merge tooling).
Move inline cloud-sessions fetch logic from Hono route handler into a
reusable getCloudSessions function in handlers.ts, and introduce new
Effect HttpApi endpoints for fetching and importing individual cloud
sessions.
- Extract getCloudSessions handler from routes.ts inline implementation
- Export fetchCloudSession, fetchCloudSessionForImport, importSessionToDb
from kilo-gateway package
- Add cloudSession (GET /kilo/cloud/session/:id) endpoint for previewing
remote session data
- Add cloudSessionImport (POST /kilo/cloud/session/import) endpoint to
download and persist cloud sessions locally
- Define CloudSession, CloudSessionData, CloudMessage schemas in the
kilo-gateway API group
- Change claw status error response from 500 InternalServerError to
503 ServiceUnavailable
- Register new cloud routes in instance router
- Add test coverage for route disambiguation between import and :id paths
- Regenerate SDK types and OpenAPI spec
Pasting into the prompt textarea left its layout stale until the next edit, so the visible content did not reflect the pasted text. Mark the layout dirty on paste and notify the content-change handler once the renderer is idle so the prompt updates immediately.
Extract shared handler logic from Hono routes into reusable functions in
kilo-gateway/server/handlers.ts and wire up new Effect HttpApi endpoints
for profile, notifications, organization switching, claw status, and
claw chat credentials.
- Add handlers.ts with pure business logic (getProfile, getNotifications,
setOrganization, getClawStatus, getClawChatCredentials)
- Define KiloGatewayApi group with typed schemas for all endpoints
- Implement Effect-based handler layer in httpapi/handlers/kilo-gateway.ts
- Register kilo gateway routes in instance router and HttpApi composition
- Add config/warnings endpoint to config group and handler
- Regenerate SDK types and client methods for new endpoints
- Update OpenAPI spec with /kilo/* and /config/warnings paths
- Export new constants (KILO_CHAT_URL, KILO_EVENT_SERVICE_URL) and
handler utilities from kilo-gateway package index
Replace the inline opncd.ai/s/ grep added to check-kilocode-change with a standalone script/check-forbidden-strings.ts. Wired into test-vscode.yml as a separate step alongside the existing marker check.
The legacy upstream share URL path pattern must not reappear in the repo. Piggyback on the existing check-kilocode-change forbidden-string grep instead of adding a new check.
Reformat code with consistent line breaks, trailing commas, semicolons,
and line-length compliance. No logic changes — purely whitespace,
indentation, and punctuation adjustments driven by the project formatter.
- Break long function signatures and conditionals across multiple lines
- Remove trailing blank lines and stray leading newlines
- Replace string-expression JSX whitespace with literal spaces
- Convert quoted object keys to unquoted where valid
- Remove erroneous shell command prefix from openapi.json
- Deduplicate SessionNetworkWait1 schema and simplify Finite unions to
plain number type in OpenAPI spec
Introduce a structured Effect HttpApi surface for all Kilo-specific
endpoints, replacing inline Hono handler logic with declarative group
definitions, typed schemas, and composable handler layers.
Key changes:
- Add HttpApi group and handler modules for commit-message, enhance-prompt,
indexing, kilocode, network, remote, session-import, suggestion, and
telemetry
- Extract allow-everything permission logic into a reusable Effect function
- Register all Kilo HttpApi groups in InstanceHttpApi and wire route
forwarding in the Hono instance router
- Export Suggestion.RequestSchema and annotate schemas with identifiers
- Use NonNegativeInt for indexing status fields and Schema.Finite for
network wait timestamps
- Add httpapi-bridge test asserting parity between Hono and Effect specs
for all 22 Kilo overlay routes
- Regenerate SDK types and openapi.json to reflect the new endpoints
Move active question and permission forms from fixed bottom panels above
the prompt into the scrollable chat transcript. Users can now scroll through
prior messages while a form is active and scroll back down to it.
- Add QuestionView and PermissionView in session/views/ with callback-based
wiring (no direct RPC access from views)
- Update SessionMessageListPanel to own optional active views, syncing them
from SessionModelEvent.StateChanged and anchoring before ProgressPanel
- Update SessionUi to create views with controller lambdas, pass them into
SessionMessageListPanel, and remove them from the SOUTH stack
- Remove unused Dock.neutral() and Dock.warning() from SessionUiStyle
- Replace QuestionPanelTest/PermissionPanelTest with faster callback-based
QuestionViewTest/PermissionViewTest under session/views/
Replace waitFor { rpc.deletes.size == N } with an awaitDeletes(n) helper
that waits on a deleteCount counter incremented by the controller's deleted
callback (fires on EDT after local.remove). This:
- Is event-driven: no time-based polling or arbitrary sleep
- Avoids EDT deadlock: waitFor pumps the event loop via invokeAndWait
rather than blocking the EDT with runBlocking { channel.receive() }
- Has no UnknownClass.warning side-effect: no runBlocking lambda at
test-method scope for the IntelliJ JUnit3 runner to misidentify
- Uses CopyOnWriteArrayList for deletes/listed in FakeSessionRpcApi to
prevent ConcurrentModificationException from concurrent coroutines
Add an animated spinner to the subagent session footer to indicate
when a subagent is actively working, matching the running status
indicator shown in the main session prompt.
Users installing with pnpm or --ignore-scripts now see a clear explanation
of why the native binary is missing and exact steps to fix it. The shell
script wrapper provides more actionable guidance than the previous Node.js
fallback that only suggested running the postinstall script without context
about why it wasn't run automatically.
Two concurrent coroutines called deletes.add and listed.removeAll on plain
ArrayList instances, causing ConcurrentModificationException that silently
killed one coroutine before it could record its result.
- Change deletes and listed in FakeSessionRpcApi to CopyOnWriteArrayList
- Add deleteSignal Channel to FakeSessionRpcApi so tests can await deletes
via event notification rather than timeout-based polling with waitFor()
- Rewrite the failing test to receive from deleteSignal (event-driven,
zero-timeout) and update the skips-already-deleting test the same way
The TUI's copy and export actions only included ~100 messages because they
read from the in-memory sync store which caps at 100 for display performance.
Now both actions fetch all messages directly from the server API.
IntelliJ Swing/coroutine tests are inherently flaky on Windows (timeout in
HistorySessionActionsTest). Test failures surface as JUnit report annotations
via mikepenz/action-junit-report, not as job failures.
Per AGENTS.md, every Kilo-specific change in shared opencode files must
carry kilocode_change markers so upstream merges can resolve mechanically.
Adds whole-file annotations to the new helper and test, single-line
annotations to the two modified lines in run.ts.
Atoms in `args["--"]` are raw passthrough per yargs `populate--`
semantics: the user typed `--` to opt out of further parsing, so
the assembler must not synthesize quote bytes around them. Re-quoting
raw atoms breaks leading-dash inputs like
kilo run -- "- Who are you?"
by emitting `"- Who are you?"` (literal quotes) into the model prompt.
Atoms before `--` keep the existing wrap-quote behavior from #4979 so
shell-bound multi-word positionals still preserve their boundaries.
Extracted the message assembler to `cli/cmd/run-message.ts` so it can
be unit-tested without pulling in the full handler's dependency tree.
Replace hardcoded paddingTop approximation with justifyContent center
on the dialog overlay so dialogs are properly centered regardless of
terminal height.
Windows Path.toString() uses backslashes which breaks the JSON
string literal in mock.path. Replace backslashes with forward
slashes before embedding in the JSON template.
- Add kilocode_change markers around Java 21 setup in test.yml (required
by annotation checker for .github/** changes)
- Fix test-ci.ts: use ./gradlew.bat (not bare gradlew.bat) on Windows so
bun's shell can locate and execute the wrapper script
- Fix HistorySessionActionsTest: delete two items races — use waitFor
instead of fixed-duration flush so both coroutine deletes complete before
asserting; sort IDs for ordering-independent comparison
- Add setup-java@v4 (temurin 21) step to test.yml so Windows runner has
the JDK required for Gradle Kotlin compilation
- Fix SessionRecoveryTest: existing-session flow (controller("ses_test"))
calls showSession() after history load, setting showSession=true;
update show=false -> show=true in 7 assertSession calls that tested
this flow
Move CLI binary verification from :backend:processResources to
buildPlugin so typecheck and test tasks work on a fresh checkout
without CLI binaries present.
processResources was in the compile/jar chain (needed by
compileTestKotlin), causing checkCli's @InputDirectory validation
to fail at configuration time when the generated/cli dir didn't exist.
checkCli is now wired to buildPlugin in the root build.gradle.kts,
which is only called during full plugin packaging.
- Add compile-only Gradle typecheck task so JetBrains CI no longer
requires CLI binaries or buildPlugin to verify Kotlin compiles
- Remove PrepareLocalCliTask from Gradle; CLI binary prep is now an
explicit step via bun run build, not triggered implicitly from
processResources
- Remove @kilocode/cli#build dependency from JetBrains typecheck in
Turbo so root typecheck and test:ci don't pull CLI bundling as a
prerequisite for JetBrains compile
- Add @kilocode/cli#build -> @kilocode/sdk#build ordering in Turbo to
prevent CLI bundling from racing with SDK generated-source cleanup
- Fix test-ci.ts: Windows gradlew.bat support, strip nested XML
declarations from JUnit reports, exit with Gradle exit code
Fixes a bug where projectors were stored with Definition object references
as Map keys but lookups were failing due to object identity mismatches.
Now uses versioned type strings as keys, ensuring events are correctly
matched to their projectors during sync processing.
This fixes issues where certain events would not be properly projected
to the read model, causing stale or missing data in views.
The VSCode UI currently shows token usage from only the current turn.
This is confusing to users and differs from what the CLI shows. This
change updates the token display to show the total token usage for the
full session, equivalent to what the CLI shows.
Implement click-to-open functionality for file mentions, allowing users to directly open files from the prompt input. Add visual distinction between file mentions and built-in mentions (@terminal, @git-changes) through conditional styling with background colors, borders, and hover effects. Enhance mention selection snapping to fully cover partially-selected mentions, and introduce keyboard handlers for atomic backspace deletion and arrow key navigation that skips cursor movement through mention tokens. Persist known paths across the session to enable proper mention rediscovery after undo operations.
aria-hidden only hides from screen readers; pointer-events: none only
blocks the mouse. Tab focus could still traverse into the hidden
sidebar's worktree buttons and session items. inert handles all three
at once: removes from the a11y tree, blocks pointer events, and prevents
keyboard focus.
Adds a toggle button left of the active session/tab title that collapses
the worktrees & sessions sidebar. The collapsed state is persisted to
.kilo/agent-manager.json, restored on panel reload and VS Code restart,
and auto-expands when the user creates a new session or worktree so the
new entry is visible. The first paint after restart skips the width
animation so the panel never flashes from open to closed.
Add syntax highlighting to shell command output using Shiki with labeled "Command" and "Output" sections, per-section copy buttons, and an "Open in Editor" action. The feature supports opening full untruncated output in VS Code editor tabs and includes i18n translations for 18 languages.
Changes include:
- BashHighlightedOutput component with shellscript grammar for commands and log grammar for output
- Section labels and dividers matching MCP tool styling patterns
- Copy buttons for both command and output sections with visual feedback
- OpenContent message type and handler for opening arbitrary text in untitled editor tabs
- Support for outputPath metadata to open full files when output is truncated
- CSS styling for section layout, scrolling, and hover-revealed actions
- i18n dictionary updates across all 18 supported languages (ar, br, bs, da, de, en, es, fr, ja, ko, nl, no, pl, ru, th, tr, uk, zh, zht)
- Changeset entry documenting the feature as a minor version bump
Add KiloBundle locale files for ar, bs, da, de, es, fr, ja, ko, nl, no,
pl, pt_BR, ru, th, tr, uk, zh_CN, zh_TW — matching the language support
already present in the VS Code extension.
Resolve remaining parity gap from PR #10097 review: VS Code's cloud
history has an 'Only this repository' checkbox that filters sessions by
git remote URL; JetBrains had the RPC plumbing but no UI or URL lookup.
- Add GitRemoteUrl.kt helper that resolves 'origin' via git subprocess
- HistoryController gains gitUrl (resolved once on first cloud load) and
repoOnly (defaults true when a URL exists); applyRepoOnly() toggles
the filter and reloads cloud history
- HistoryPanel adds a JBCheckBox on the cloud tab, visible only when a
git remote URL is found, with left indent aligned to list item text
- Add bundle key history.cloud.repo.only
- Extend HistoryControllerTest with 8 new cases covering URL filtering,
null fallback, load-more retention, and checkbox panel behaviour
The troubleshooting page was deleted earlier in this PR with a redirect
to the wasteland index, but several inline links still pointed at the
old path. Lychee link-checker treats those as broken because it
validates files on disk rather than honoring redirects. Repoint them at
/docs/code-with-ai/gastown/wasteland directly.
Defining FitOnResize inside the parent render gave it a new component
identity on every parent render, forcing React to unmount/remount it
and tear down the ResizeObserver each time. Hoist it to module scope
and pass useReactFlow in as a prop. Also drop the unused instanceRef.
Update the mobile apps page to reflect that the Android app is now available on Google Play and provide a link for installation.
Added detailed information about mobile app capabilities, including session management, KiloClaw chat, and Cloud Agent spawning. Included new screenshots to illustrate the mobile interface and added a section for the iOS app waitlist.
The picker called setFetchedModels(undefined) unconditionally after
"Add Selected", wiping the remaining un-picked models. Users had to
re-fetch to add a subset twice in a row.
Filter the picked IDs out of fetchedModels and clear the selection.
Only close the picker when every fetched model has been added.
Refs: #10139
Add optional `escapeJson` parameter to `ConfigPaths.substitute` to control
whether file content should be JSON-escaped. When `false`, multiline content
and special characters are preserved as-is, which is required for agent
markdown prompts that need raw file content rather than escaped strings.
Update agent config processing to pass `escapeJson: false` when substituting
file content into markdown prompts, ensuring proper handling of multiline
files without unwanted escape sequences.
Add comprehensive test coverage for the new parameter and existing
substitution functionality.
Enable file content substitution in agent configuration prompts using the
existing `ConfigPaths.substitute` utility. This allows agent markdown files
to reference external file contents via `{file:path}` syntax, with missing
files resolving to empty strings.
Export `substitute` function from ConfigPaths to support agent config
processing.
The DialogAlert component was rendering '\n' literally instead of
converting it to actual line breaks. This fix:
- Imports For from solid-js for proper list rendering
- Uses flexDirection='column' to stack lines vertically
- Replaces escaped \n with actual newlines before splitting
This affects the Teams tab message which displays:
'You're not a member of any teams.\nVisit https://app.kilo.ai...'
Adds a test that verifies cancel() on a session with no active tail
does not leave stale entries in the internal maps (versions, targets,
latest, activeSince). Also adds _hasInternalState() debug helper to
verify map cleanup.
* chore(deps): add minimum release age to bun install config
Set `minimumReleaseAge` to 410520 seconds (~4.75 days) to avoid
installing recently published package versions that may be unstable
or malicious.
* Update bunfig.toml
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
---------
Co-authored-by: kilo-code-bot[bot] <240665456+kilo-code-bot[bot]@users.noreply.github.com>
* fix: catch EEXIST from recursive mkdir on Windows
fs.mkdir with { recursive: true } can still throw EEXIST on Windows
when the target directory is backed by an NTFS reparse point (OneDrive),
a directory junction, or a WSL-served path. libuv's recursive walk
doesn't treat these as regular directories, so mkdir with recursive:true
attempts to create an already-existing path segment and fails.
This adds a defensive EEXIST catch at both directory-creation origins:
- AppFileSystem.ensureDir / writeWithDirs (snapshots, config, plans)
- Encoding.write (all tool writes and edits)
No functional change on Linux/macOS where EEXIST is never thrown from
recursive mkdir.
Fixes#9618, #9755
* fix: remove extra arg from mkdirSafe call, add unit tests
* docs(kilo-docs): update auto-generated source links
Add 2 new GitHub issue references (9618, 9755) from encoding.ts
and update URL count from 84 to 86.
---------
Co-authored-by: nimgrim <nimgrim@users.noreply.github.com>
Co-authored-by: Imanol Maiztegui <imanol.mzd@gmail.com>
String.length counts code points, not display columns, so CJK
characters and emoji that occupy two terminal cells caused
misaligned cursors, broken mention triggers, and incorrect
history restoration offsets.
Use Bun.stringWidth for now, we need an alternative for this.
Fix#26716Close#26922
Switches all webview input ::placeholder rules to var(--vscode-input-placeholderForeground, var(--text-weaker)) so placeholders pick up the VS Code-native placeholder color and stay visually distinct from typed values across Settings (including indexing fields), Agent Manager dialogs, prompt input, model search and kiloclaw.
Supersedes #10085 by sylwester-liljegren.
DOMPurify 3.1.7+ removed foreignObject from default HTML integration
points, so the inner <div>/<span>/<p> Mermaid renders inside foreignObject
were stripped, leaving every shape with empty text. Restore it via
HTML_INTEGRATION_POINTS.
- Add DeepSeek to the Standard API keys list on the BYOK page (Kilo-Org/cloud#3167)
- Update auto-model-tiers architecture doc to reflect the new default of kilo-auto/free for all new users (Kilo-Org/kilocode#10151)
- Add test:ci script (./gradlew test --continue) that runs all JetBrains
Kotlin tests and collects JUnit XML results into .artifacts/unit/junit.xml
- Script always exits 0 so CI reports failures without blocking
- Add @kilocode/kilo-jetbrains#test:ci Turbo task depending on typecheck
- Fix 7 stale SessionRecoveryTest assertions that assumed kilo/gpt-5 as
the default model after the default changed to kilo-auto/free in main
Test suite: 658 frontend + 234 backend tests, ~6m 35s on local machine
\S+ was greedily consuming trailing punctuation (. ! , ;) into the URL
match, causing new URL() to mutate clean ASCII URLs — e.g.
"see https://example.com." became "see https://example.com./".
Fix: strip trailing sentence punctuation before parsing, extract and
replace only the hostname (not href) to avoid adding trailing slashes to
bare origins, and restore the stripped tail afterward.
Move Kilo-specific URL normalization logic out of shared upstream files
and into a mirror file under src/kilocode/, with kilocode_change markers
at each call site per the fork merge minimization convention.
Prevent homograph attacks where visually identical Unicode characters
(e.g. Cyrillic а vs Latin a) could trick users into approving malicious
URLs in bash and webfetch permission prompts.
* fix(tool): clarify semantic_search returns snippets not file paths
The first description bullet read "Find files most relevant to the
search query using semantic search.", which led an AI agent to tell a
user that the tool returns file paths only. The tool actually returns
matching content with file paths, line ranges, and relevance scores.
Updates the first two description bullets to name the output shape
directly. No runtime change.
Closes#9767.
* test(cli): cover semantic_search description
---------
Co-authored-by: marius-kilocode <marius@kilocode.ai>
This flag currently does nothing. Presumably, it was recently added by
OpenCode upstream, but since Kilo already has the `--auto` flag, the
code that would handle `--dangerously-skip-permissions` is wired into
`--auto` instead.
Removing this useless flag avoids confusion for users.
Avoids the ls-remote + merge-base --is-ancestor walk in last() for the
common case by reading the recorded tag from .opencode-version. merge.ts
writes the file as part of the pre-merge compat commit so future runs of
fix-kilocode-markers, reset-to-upstream, and find-reset-candidates can
resolve the base tag instantly. Seeded with v1.14.33 (PR #9978).
git rerere learns conflict resolutions from past upstream merges and
replays them on the next merge. When past resolutions used the buggy
mergeWithNewestVersions ordering, rerere auto-resolves package.json
files with stale content before transformConflictedPackageJson ever
gets a chance to run — so the fixed merge logic never reaches the
file.
Add reconcileAllPackageJson, which runs after every merge (clean,
auto-resolved, or partially conflicted) and rewrites every package.json
that the merge touched from the kilo branch's pre-merge HEAD and the
opencode compat branch using the same merge logic. Files that are
still conflicted are skipped so manual resolution isn't silently
overwritten.
This makes our merge logic the source of truth for package.json
content, regardless of what rerere or git's textual merge produced.
Seeding the result with theirs' keys and appending ours-only keys at the
end caused kilo-only deps (e.g. rotating-file-stream in packages/core)
to relocate from the middle of the deps block to the end during the
pre-merge transform. Git's textual 3-way merge then saw ours keeping
the line in place and theirs adding the same key elsewhere, producing
a duplicate JSON key in the merged file.
Iterate ours first so kilo-only deps stay in their original position,
then append any theirs-only keys at the end.
The transform that materialises the 'kilo compat for vX.Y.Z' commit during
an upstream merge takes upstream's package.json wholesale and re-applies a
hand-picked list of Kilo scripts. That list was incomplete: it only covered
`extension`, `changeset`, `changeset:version`, `test`, and `test:ci`, so
every merge silently dropped Kilo's `postinstall` tail (`&& bun run
script/setup-git.ts`) and the `dev-setup` root shortcut, and it never
pruned upstream-only scripts (`dev:desktop` / `dev:web` / `dev:console`)
or upstream-only catalog entries (`@sentry/solid`,
`@sentry/vite-plugin`) whose target packages Kilo doesn't ship.
- replace the per-script if-blocks with data-driven PRESERVE_SCRIPTS
- add DELETE_UPSTREAM_SCRIPTS for scripts that reference packages Kilo
doesn't ship
- add DELETE_UPSTREAM_CATALOG for catalog entries with zero Kilo consumers
- apply the same policy in both transformPackageJson (conflict path) and
transformAllPackageJson (pre-merge sweep path) — previously the
pre-merge sweep was missing `changeset` / `changeset:version`
preservation
- new tests covering preservation, deletion, opencode test scripts, and
the catalog pruning
The automated kilo compat transform keeps upstream's root scripts/catalog
wholesale and only re-applies a handful of Kilo-specific scripts, which
silently dropped:
- postinstall's `&& bun run script/setup-git.ts` tail (needed to set
merge.conflictStyle=zdiff3 locally, which upstream merges rely on)
- the `dev-setup` script shorthand
- kept dead `dev:desktop` / `dev:web` / `dev:console` scripts whose
target packages aren't tracked in Kilo
- kept `@sentry/solid` / `@sentry/vite-plugin` catalog entries that
have zero consumers in our tree
* fix(vscode): fix cursor positioning when text ends with newline
A trailing newline is collapsed in a <div> with white-space: pre-wrap
but renders as a real empty line in the <textarea>. Without an extra
<br>, the overlay ends up one line shorter than the textarea, which
desyncs scrollTop and makes the visible caret appear one line off from
where the textarea actually inserts text.
* docs(vscode): simplify comment explaining trailing newline br element
Update `findLatestCompatCommit` to use semantic versioning when identifying the latest compatibility commit. This ensures the correct commit is selected even when upstream tags diverge or are not strictly linear.
- Add semver parsing and comparison utilities
- Implement `targetSemver` to resolve versions from tags or commit messages
- Filter and sort compatibility candidates by version relative to the target version
- Add test case for diverging upstream tags
Update the upstream merge script to identify and link to the previous compatibility commit. This ensures that pre-merge transformations maintain a proper commit history by using multiple parents when a prior compatibility base is found, rather than creating disconnected commits.
- Add `findLatestCompatCommit` to locate previous compatibility commits
- Implement `commitTree` and `updateBranch` for low-level git manipulation
- Update `merge.ts` to integrate compatibility base detection and multi-parent commits
* fix(vscode): fix cursor positioning when text ends with newline
A trailing newline is collapsed in a <div> with white-space: pre-wrap
but renders as a real empty line in the <textarea>. Without an extra
<br>, the overlay ends up one line shorter than the textarea, which
desyncs scrollTop and makes the visible caret appear one line off from
where the textarea actually inserts text.
* docs(vscode): simplify comment explaining trailing newline br element
Avoids the ls-remote + merge-base --is-ancestor walk in last() for the
common case by reading the recorded tag from .opencode-version. merge.ts
writes the file as part of the pre-merge compat commit so future runs of
fix-kilocode-markers, reset-to-upstream, and find-reset-candidates can
resolve the base tag instantly. Seeded with v1.14.33 (PR #9978).
git rerere learns conflict resolutions from past upstream merges and
replays them on the next merge. When past resolutions used the buggy
mergeWithNewestVersions ordering, rerere auto-resolves package.json
files with stale content before transformConflictedPackageJson ever
gets a chance to run — so the fixed merge logic never reaches the
file.
Add reconcileAllPackageJson, which runs after every merge (clean,
auto-resolved, or partially conflicted) and rewrites every package.json
that the merge touched from the kilo branch's pre-merge HEAD and the
opencode compat branch using the same merge logic. Files that are
still conflicted are skipped so manual resolution isn't silently
overwritten.
This makes our merge logic the source of truth for package.json
content, regardless of what rerere or git's textual merge produced.
Seeding the result with theirs' keys and appending ours-only keys at the
end caused kilo-only deps (e.g. rotating-file-stream in packages/core)
to relocate from the middle of the deps block to the end during the
pre-merge transform. Git's textual 3-way merge then saw ours keeping
the line in place and theirs adding the same key elsewhere, producing
a duplicate JSON key in the merged file.
Iterate ours first so kilo-only deps stay in their original position,
then append any theirs-only keys at the end.
The transform that materialises the 'kilo compat for vX.Y.Z' commit during
an upstream merge takes upstream's package.json wholesale and re-applies a
hand-picked list of Kilo scripts. That list was incomplete: it only covered
`extension`, `changeset`, `changeset:version`, `test`, and `test:ci`, so
every merge silently dropped Kilo's `postinstall` tail (`&& bun run
script/setup-git.ts`) and the `dev-setup` root shortcut, and it never
pruned upstream-only scripts (`dev:desktop` / `dev:web` / `dev:console`)
or upstream-only catalog entries (`@sentry/solid`,
`@sentry/vite-plugin`) whose target packages Kilo doesn't ship.
- replace the per-script if-blocks with data-driven PRESERVE_SCRIPTS
- add DELETE_UPSTREAM_SCRIPTS for scripts that reference packages Kilo
doesn't ship
- add DELETE_UPSTREAM_CATALOG for catalog entries with zero Kilo consumers
- apply the same policy in both transformPackageJson (conflict path) and
transformAllPackageJson (pre-merge sweep path) — previously the
pre-merge sweep was missing `changeset` / `changeset:version`
preservation
- new tests covering preservation, deletion, opencode test scripts, and
the catalog pruning
The automated kilo compat transform keeps upstream's root scripts/catalog
wholesale and only re-applies a handful of Kilo-specific scripts, which
silently dropped:
- postinstall's `&& bun run script/setup-git.ts` tail (needed to set
merge.conflictStyle=zdiff3 locally, which upstream merges rely on)
- the `dev-setup` script shorthand
- kept dead `dev:desktop` / `dev:web` / `dev:console` scripts whose
target packages aren't tracked in Kilo
- kept `@sentry/solid` / `@sentry/vite-plugin` catalog entries that
have zero consumers in our tree
The cancel() function was always incrementing and storing a version in the
versions map, even for sessions with no queued prompts. Since cleanup only
happens in enqueue's release phase, sessions without active tails left
permanent map entries.
Now cancel() checks if the session has an active tail before modifying state.
If no tail exists, it cleans up any existing versions/targets/latest/activeSince
entries instead of creating new ones.
Add assertQuestionReply() to SessionControllerTestBase and a local
assertReply() in QuestionPanelTest that render reply triples as
"<id> <dir> [[A],[B]]" — consistent with the codebase's string-diff
assertion style.
Render all question items instead of only the first, with per-item option
selection and a single Submit button. Add JsonSessionStreamTest covering
the full assistant-text → two-question → reply flow.
- Replace session.selected() with session.configModel() in NewWorktreeDialog to reflect the configured model rather than the selected session model.
- Add configModel to SessionContext and implement an effect that clears session overrides matching the old config model when the global config model changes, ensuring sessions pick up the new config model.
PR #25418 replaced Instance.disposeAll with the disposeAllInstances helper
re-exported from test/fixture/fixture. Match the pattern used by the
sister tests in test/kilocode/.
The src/util barrel was split into per-file modules in main; every other
test in test/kilocode/ now imports Log from @opencode-ai/core/util/log
directly. Match the pattern.
Rename SessionStyle → SessionEditorStyle and SessionStyleTarget →
SessionEditorStyleTarget throughout to better reflect that this type
carries editor-derived styling (fonts, colors, scheme) applied to
session UI components.
Update ProgressPanel, SessionLayout, and CompactionView to use the
canonical Gap method names (md, small, lg) now that the old aliases
(inline, part, regular) were removed along with UiStyle.Space.
Replace all UiStyle.Space.* constant usages with the corresponding
UiStyle.Gap.*() functions throughout the JetBrains plugin UI code.
Also fixes a pre-existing double-scale bug in EmptySessionPanel where
JBUI.scale(UiStyle.Gap.pad()) was called instead of UiStyle.Gap.pad().
When the consumer (readLines) hits the line/byte cap and destroys the
PassThrough, the underlying createReadStream had no link back and would
keep reading chunks to EOF in the background, defeating the early-exit
optimisation for large files.
Optimistically stream the file as UTF-8 -- the common case -- using a
fatal-mode TextDecoder so the read tool can stop pulling bytes from
disk once the line / 50KB byte cap is hit. Only fall back to a
full-buffer iconv decode when the bytes turn out not to be valid UTF-8.
The streaming + retry logic lives in a new kilo helper
(packages/opencode/src/kilocode/text-stream.ts) so the read tool's
`lines` function stays close to upstream OpenCode shape.
The existing apply_patch encoding test only checked final file bytes,
which were correct because Patch.deriveNewContentsFromChunks does its
own encoding-aware read. The diff and additions/deletions counts
returned to the user (and shown in the permission prompt) were
nonetheless garbled because the surrounding tool reused a hard-coded
UTF-8 decoder. Pin the diff metadata to catch that regression.
Bom.readFile uses a hard-coded UTF-8 TextDecoder, so the oldContent
captured for the diff, additions/deletions counts, and permission-prompt
metadata was mojibake for any non-UTF-8 file. The actual bytes written
were correct because deriveNewContentsFromChunks already does
encoding-aware reads, but the user-visible diff did not reflect the real
file contents. Switch to EncodedIO.read to match.
* feat(diff-viewer): add base branch picker to workspace diff source
Introduce a UI control that lets users override the comparison base
branch in the diff viewer. The picker lists local and remote branches
sorted by commit date, with a "Default" option that falls back to the
auto-resolved tracking/default branch.
Key changes:
- Add `listBranches` to GitOps for sorted branch enumeration
- Extend DiffSourceCatalog with base branch override state and disposal
- Add `reactivate` method to SourceController for in-place source rebuild
- Create shared BranchSelect component (moved from agent-manager)
- Add BaseBranchPicker component for the diff viewer header
- Wire new webview messages (requestBranches, setBaseBranch, branches)
- Add i18n keys for all supported locales
- Register DiffSourceCatalog as disposable in extension activation
* refactor(diff-sources): extract staged and unstaged git diff sources into standalone modules
Decompose the diff source system by introducing dedicated modules for
staged (index vs HEAD) and unstaged (working tree vs index) views,
alongside shared git-status parsing utilities.
- Create git-status.ts with reusable parseNameStatus, parseNumstat,
showBlob, readDisk helpers and the summarize builder
- Implement staged.ts source using `git diff --cached` against HEAD
- Implement unstaged.ts source combining tracked diffs with untracked
file enumeration via `git ls-files --others`
- Register both sources in DiffSourceCatalog when a workspace root exists
- Extend DiffSourceType union with "staged" and "unstaged" variants
- Rename workspace label from "Local Changes" to "Branch" and add
i18n entries for the new source picker options
* feat(vscode): display current branch in diff viewer base branch picker
Show the currently checked-out branch (HEAD) alongside the base branch
selector with an arrow indicator (current → base), providing clearer
context for which branches are being compared in the diff viewer.
* refactor(diff): replace magic empty string with named INDEX_REF constant and fix disposal
Extract `INDEX_REF` constant in git-status module to clarify intent when
referencing the staging area instead of a commit. Update staged and
unstaged sources to use it. Additionally:
- Clear `baseBranchOverride` on dispose to prevent stale state
- Apply `generatedLike` detection to staged diff source
- Update tests to reflect new disposal semantics
* fix(vscode): move baseBranchOverride state from catalog to provider
Relocate the base branch override from DiffSourceCatalog into
DiffViewerProvider where it belongs as panel-level state. Pass it
through PanelContext so the catalog remains stateless and testable.
- Add `baseBranchOverride` field to PanelContext type
- Thread override via ctx in DiffViewerProvider.openPanel and setBaseBranch
- Remove setBaseBranchOverride/getBaseBranchOverride from catalog
- Accept override as parameter in listWorkspaceBranches
- Simplify catalog dispose and update tests accordingly
* feat(i18n): add staged/unstaged diff source labels and rename workspace to branch
Introduce translated strings for the new "staged" and "unstaged" diff
viewer source options across all 18 locale files. Rename the existing
workspace source label from "Local changes" to "Branch" in each
language to better reflect its scope.
* test(vscode): update diff source catalog tests to include staged and unstaged entries
Align test expectations with the newly added staged/unstaged diff
sources. The listAvailable assertions now verify that both "staged"
and "unstaged" appear alongside "workspace" in the returned source
list.
* fix(vscode): add path traversal protection and size guards to diff sources
Introduce `resolveInside` to reject absolute paths and `..` traversal
that could escape the workspace directory. Replace raw `path.join`
calls in `readDisk`, `fileSize`, and unstaged file lookups with the
safe resolver.
Add `blobSize` and `fileSize` helpers to check content length before
reading, skipping detail fetches for files exceeding MAX_DETAIL_BYTES
in both staged and unstaged sources. Re-export MAX_DETAIL_BYTES from
git-status for shared access.
* fix(diff): resolve override branch refs via remote fallback
When `baseBranchOverride` is a short remote-tracking name (e.g.
`feature` from `refs/remotes/origin/feature`), `git merge-base` fails
because no local branch exists. Add `resolveOverrideRef` that attempts
`rev-parse --verify` on the short name first, then falls back to
`origin/<name>` before giving up entirely and resuming auto-detection.
* fix(vscode): use lstat for symlink-safe working-tree reads
Replace `fs.stat` with `fs.lstat` in `readDisk`, `fileSize`, and
unstaged file enumeration to avoid following symlinks. For symlink
entries, `readDisk` now returns the link target string (matching git's
blob storage) instead of reading the pointed-to file's contents.
This prevents untracked symlinks from leaking arbitrary file contents
(e.g. `~/.aws/credentials`) into the diff viewer, since `resolveInside`
only guards against lexical path traversal, not symlink dereferencing.
* refactor(diff): propagate mtime-based stamps for untracked file cache invalidation
Untracked files always report additions/deletions as 0 since numstat
cannot compute them without an index blob. This made the webview cache
unable to detect edits to untracked files, leaving stale content visible
between polling cycles.
Introduce an optional `stamp` field on `FileEntry` that encodes
size+mtime for untracked entries, and thread it through `summarize()`
and `fetchFile()` so cache keys update whenever the file is modified on
disk. Tracked entries continue using the numstat-derived stamp as before.
* fix(vscode): log for-each-ref failures in listBranches instead of silently swallowing
Replace the empty `.catch(() => "")` with a handler that logs the
error message before returning the fallback empty string, improving
debuggability when branch enumeration fails.
- Add tip callout to openai.md pointing ChatGPT subscribers to the Plus/Pro page
- Expand openai-chatgpt-plus-pro.md with intro, recommended models table,
enriched tips, limitations, and FAQ sections sourced from blog post
https://blog.kilo.ai/p/use-chatgpt-subscription-inside-kilo
Addresses review feedback: nonInteractiveEnv() preserves an inherited
GIT_SSH_COMMAND, so unconditionally passing allowUnsafeSshCommand=true
would reopen the vector simple-git 3.36.0 closes. Gate the flag on
isKiloOwnedSshCommand() so we only bypass the check for our fixed
'ssh -o BatchMode=yes' value; inherited commands are rejected as
before.
simple-git 3.36.0 blocks GIT_SSH_COMMAND by default. Our
nonInteractiveEnv() intentionally sets it to 'ssh -o BatchMode=yes'
to prevent passphrase popups during background fetches, so enable
the allowUnsafeSshCommand opt-in on the instance that uses it.
Picks up expanded blocking of exploitable git config keys (core.fsmonitor,
--template, merge-related) and GIT_CONFIG_COUNT env var. No breaking API
changes for our usage — the only removed export (ParsedVulnerabilities)
is not referenced anywhere in the repo.
Kilo isn't always BYOK; what matters here is that Kilo doesn't charge a
per-request fee on top of the upstream inference cost. So for the Kilo
provider, the gateway/marketplace `cost` would understate the user's true
spend — always prefer the upstream/market cost when present.
- Add SessionState.Loading and handle it in ProgressPanel and isBusy()
- Deduplicate setState calls in SessionModel (no-op when state unchanged)
- HistoryController now opens cloud items as SessionRef.Cloud instead of importing inline
- HistoryModel tracks loaded flag; HistoryPanel shows a loading card before first load
- SessionManager interface takes SessionRef instead of raw SessionDto
- build.gradle.kts: set splitModeServerPort for runIdeBackend task
- Test: NewSessionActionTest, SessionUiTestBase, SessionModelTest updated accordingly
Replace duplicated sessionId/cloud/initialSession controller fields with a single mutable
ref: SessionRef? computed from the incoming target. Explicit local and cloud session loads
now show the session view on completion instead of falling back to recents. Recents can
only run on blank controllers (ref == null, sessionLoadState Idle, showSession false) via
a canUseRecents() guard applied at all recents entry points. SessionRef gains id, type,
and a from()/resolve() parser so id-only Local refs are possible. SessionSidePanelManager
cache keys switch to ref.key/cacheKey and cloud-imported sessions can be reused by their
local id after import. Tests cover empty-explicit-session-shows-session, no-recents-
during-load, cloud import isolation, ref snapshot assertions, and cloud-to-local reuse.
* docs: verify and update wasteland workflow + admin pages against source code
- workflow.md: update stamp dimensions to reflect actual stamps.valence
JSON structure (quality + reliability), confirmed quality enum
(excellent/good/fair/poor), note evidence must be a valid URL,
clarify wl unclaim is the abandon mechanism (no gt_wasteland_abandon)
- admin.md: update posting fields to show which are API-exposed vs
wl-CLI-only, add review inbox owner+admin requirement callout,
update inbox card kinds to match classifier (add Unknown), confirm
quality enum in stamping section, note trust_level 0 for soft ban,
add rig trust levels and PR management to permissions matrix,
clarify two-tier API enforcement (member vs owner), update
Create Your Own TODO with WS-Admin 7 ship status
- concepts.md: update quality scale to use enum values not 1-5,
replace wild-west mode with direct mode terminology, add confidence
field reference, update TODO for Mayor tool name
- quick-start.md: update quality scale to match confirmed enum
* docs(wasteland): add admin settings section, PR commenting, and accuracy fixes
- Add Admin Settings section to admin.md covering test admin access,
pending PRs, rig management, and delete wasteland warnings
- Add Commenting on PRs subsection to review inbox
- Document admin-action subkinds (accept-upstream, close-upstream)
in the review inbox card types
- Fix flowDiagram height attribute per spec (550 not 550px)
Write full content for wasteland/quick-start.md (8-section happy path
from prerequisites to getting stamped) and wasteland/settings.md (7
sections covering connection, upstream, rig handle, DoltHub PAT,
filters, auto-submit, and admin settings). Include BrowserFrame
placeholders, security callouts for fine-grained DoltHub PATs, and
TODO: verify markers for unverified claims.
* docs(wasteland): flesh out Overview and Concepts pages
- index.md: hero paragraph, What is the Wasteland, federation model with flowDiagram, roles table, Gas Town by Kilo benefits, navigation links, 4 BrowserFrame placeholders (settings, wanted board, mayor claiming, claim detail drawer)
- concepts.md: 11 H2 sections covering Wasteland instance, federation, rig identity, wanted board, item lifecycle with flowDiagram, claims, evidence, stamps, reputation ledger, validators, DoltHub PRs
- All unverified claims marked with TODO: verify comments
- Cross-links to workflow, admin, and settings pages with /docs/ prefix
* docs(wasteland): add placeholder screenshot images and TODO comments
* feat(docs): add Wasteland Flow diagrams (federation, lifecycle, claim-to-stamp)
* fix(docs): add px units to flowDiagram height attributes
Reviewers flagged that unitless height values render as invalid CSS
because Markdoc supplies them as strings. Adding px suffix matches
all existing FlowDiagram usages in the codebase.
* docs(kilo-docs): scaffold Wasteland docs section
Add stub pages for the Wasteland federated work protocol under
gastown/wasteland/ and register them in the code-with-ai nav.
SideNav only renders one level of subLinks, so Wasteland pages are
flattened into the Gastown subLinks list with a 'Wasteland: ' prefix.
Content for each stub will be filled in by later beads in the convoy.
* docs(kilo-docs): noindex Wasteland stub pages until content lands
Adds a noindex frontmatter flag (read by _app.tsx, emits a robots
noindex,nofollow meta tag) and applies it to the 7 Wasteland stub
pages. Stubs are intentionally thin in this scaffolding PR;
follow-up beads will flesh them out and remove the flag.
* feat: support Kilo-hosted indexing embeddings
* fix: format indexing settings
* fix: serialize local model persistence
* fix: annotate local model persistence
* fix: stabilize MCP OAuth browser test
* fix: annotate MCP OAuth test wait
* fix: keep KiloProvider under line cap
* fix: align Kilo indexing auth defaults
* fix(vscode): add missing indexing translations
* feat(indexing): fetch Kilo embedding model catalog
* fix(indexing): align Kilo embedding metadata fallback
* fix(gateway): remove unused indexing dependency
* fix(indexing): keep fallback catalog webview safe
* fix(agent-manager): include embedding model provider
* fix(vscode): provide embedding models in stories
* refactor(indexing): rely on Cloud embedding catalog
* fix(indexing): hydrate Kilo model metadata from Cloud
* fix(indexing): clear model when switching provider
* fix(ui): correct diff line numbers by padding hunks to their real file positions
When reconstructing before/after content from patches, hunks starting
at lines other than 1 were rendered starting at line 1. Pad blank lines
before each hunk so content aligns with actual file line numbers. Also
add hunkSeparators="simple" prop across all diff viewer instances and
guard against undefined patch parse results.
* refactor(diff): replace content reconstruction with Pierre's native FileDiffMetadata rendering
Migrate all diff viewers from manually reconstructing before/after strings
to passing FileDiffMetadata directly to Pierre's renderer. This ensures
hunk headers are the source of truth for line numbers without requiring
blank-line padding.
Key changes:
- Rename `contents()` to `normalize()` and return FileDiffMetadata
alongside before/after text for legacy consumers
- Introduce discriminated union DiffProps (DiffPair | DiffPatch) so
components accept either before/after or a pre-parsed fileDiff
- Thread `patch` field through openDiff payloads and DiffVirtualProvider
- Update DiffVirtualApp, PermissionDiff, and message-part to use the
new `normalize()` API and render via fileDiff prop
- Add test coverage verifying hunk start lines are preserved without
padding
BREAKING CHANGE: `contents()` export from session-diff is removed; consumers must migrate to `normalize()`
* fix(diff): normalize trailing newline in text() helper output
* refactor(ui): remove before/after fields from diff payload interfaces
The diff pipeline now relies exclusively on patch strings for rendering
and opening diffs. This eliminates the redundant before/after content
fields from DiffVirtualFile, PermissionFileDiff, OpenDiffFn, and
ApplyPatchFile interfaces across all packages.
- Drop before/after from all diff-related type definitions
- Simplify normalize() call sites to require only patch presence
- Make DiffText type private (no longer exported from session-diff)
- Update edit tool to render from tool input during pending state
- Fix DiffVirtualApp to nest markdown view inside patch guard
- Adjust contract tests to match new fallback behavior
* fix(kilo-ui): Move session-diff normalization logic into kilo-ui package
* refactor(ui): decouple DiffProps type hierarchy between shared and kilo-ui packages
Simplify the shared ui package's DiffProps back to a single concrete
type requiring before/after contents, and relocate the discriminated
union (DiffPair | DiffPatch with optional FileDiffMetadata) into the
kilo-ui package where patch-based rendering is actually needed.
- Revert shared DiffProps to a flat type without fileDiff variant
- Define extended DiffProps union in kilo-ui/src/pierre/index.ts
- Update kilo-ui diff components to import from local pierre module
- Expand OpenDiffFn signature with optional before/after fields
Move the new Anthropic Messages, OpenAI Responses and Vercel AI Gateway
cost-extraction tests out of the shared upstream `test/session/compaction.test.ts`
file into `test/kilocode/provider-cost.test.ts` to keep Kilo-specific test
coverage in a Kilo-owned location and minimize merge conflicts with upstream.
Refactor providerCost to read `usage.raw.cost_details.upstream_inference_cost`,
which both `@ai-sdk/anthropic` (`convertAnthropicUsage`) and `@ai-sdk/openai`
(`convertOpenAIResponsesUsage`) populate with the verbatim OpenRouter usage
object. This unifies the Anthropic Messages and OpenAI Responses cost paths
through a single branch and removes the redundant `metadata.anthropic.usage`
branch (the SDK exposes the same data under both keys for Anthropic, and only
under `raw` for Responses).
They're upstream opencode comments, not kilo changes, so they
shouldn't live inside kilocode_change markers — and outside the
markers they add noise to this PR's diff. Drop them.
Move KILO_CONFIG_DIR profile fallback tests out of the shared upstream
instruction.test.ts into packages/opencode/test/kilocode/instruction.test.ts
to reduce future merge conflicts with opencode.
Restores the `postinstall` tail (`bun run script/setup-git.ts`, needed for
repo-local `merge.conflictStyle=zdiff3`) and the `dev-setup` script shorthand,
and drops `dev:desktop` / `dev:web` / `dev:console` plus `@sentry/solid` and
`@sentry/vite-plugin` catalog entries — none of which have Kilo consumers.
Refs #10003.
Add missing kilocode_change marker to the editorContext param in
the environment Effect.fn implementation; the interface signature
already had a marker but the implementation didn't.
For the Anthropic Messages API (via OpenRouter or Vercel AI Gateway), the
top-level `cost` field is the gateway fee that Kilo paid (typically 0 for
BYOK), not the user's true spend. Only use `upstream_inference_cost` /
`marketCost`; fall back to the token-based calculation when those are
absent.
Allow Azure provider connections to capture resource names or endpoint URLs so GPT-5 deployments can use the native Azure path instead of generic OpenAI-compatible setup.
Adopt the SEO-optimized titles proposed by Arkadiy based on Search Console
data. Updates the frontmatter title (and matching H1) on the CLI, VS Code,
and JetBrains platform pages, and adds a Next.js <Head> override on the
docs homepage so it gets a custom <title> instead of the default
'Kilo Code Documentation'. The JetBrains title follows the same pattern
as VS Code since the Slack proposal was truncated.
Extend the "Open in Diff Viewer" icon button to appear on Write tool
calls, not just Edit. Refactor shared CSS selectors to use generic
data-slot names (tool-trigger-actions) so both triggers share styling.
The CLI backend propagates each subagent's total into its parent
assistant message when the subagent finishes. The webview was then
walking the session family tree and summing every session's cost, which
re-added the propagated amounts once per descendant.
Compute per-session own-cost by subtracting direct children's totals
from their parent. The breakdown entries now sum to the root session's
propagated cost, matching what 'kilo stats' reports.
Cost reporting already worked when Kilo used OpenRouter chat completions
internally. Extend providerCost to also read cost from the Anthropic
Messages API stream metadata, covering both OpenRouter (Anthropic-style
`usage.cost` / `cost_details.upstream_inference_cost`) and Vercel AI
Gateway (`gateway.cost` / `gateway.marketCost`).
Revert the file-wide marker shape fixes from fix-kilocode-markers.ts
since they touch unrelated code. Scope this PR to the two review
findings in the gpt-5 block:
- Replace nativeOpenAI refactor with upstream's if (===||===) form
plus inline // kilocode_change markers on the added npm entries;
restores the upstream reasoningSummary comment.
- Restore the upstream textVerbosity comments, keep the new provider
gate wrapped in kilocode_change start/end.
- Reverts the nativeOpenAI refactor; restores upstream's reasoningSummary
guard structure + comment so added npm entries stay inside a single
marker block.
- Includes the opencode textVerbosity comment that was dropped.
- Also fixes pre-existing marker shape issues elsewhere in the same file
flagged by script/upstream/fix-kilocode-markers.ts.
Minimizes the diff from upstream opencode by restoring upstream's
original reasoningSummary guard structure and comment, and scoping
kilocode_change markers to only the Kilo-specific additions:
two extra provider npm names and the new textVerbosity provider gate.
Keep upstream's `question` tool binding and `questionEnabled` boolean
names, restore upstream's `tool.plan` position at the end of the builtin
array, and group Kilo-only additions in a single marker block. Removes
outer markers that were wrapping unchanged upstream lines as Kilo-owned
scope.
Three new/extended sections capturing patterns that repeatedly caught us off-guard during the v1.14.33 merge:
- 6.5 Scan auto-merged files for latent bugs. Not every problem surfaces as a conflict marker: duplicate declarations, duplicate manifest keys, orphaned imports, and partially-applied auto-merges that reference names from paths Kilo stubbed out.
- 9.5 Handle downstream API renames as separate commits. An upstream rename auto-merges cleanly in shared code but cascades into Kilo-only files. Keep the behavioural merge commit focused; land the mechanical cascade in follow-ups.
- 9.6 Handle upstream-added tests that diverge from Kilo. Upstream tests can encode contracts Kilo intentionally breaks, intercept seams that dependency injection now bypasses, or assume serialization shapes Kilo's extensions violate. Rewrite, skip, or delete — with a kilocode_change breadcrumb.
- Common pitfalls: added ambient-state / dependency-injection / serialization / rule-ordering / environment-divergence / lockfile-sync bullets, phrased generically so they apply beyond any one technology stack.
- Strip ~530 lines of UI guide duplication from packages/kilo-jetbrains/AGENTS.md;
the jetbrains-ui-style skill is more comprehensive and is now the source of truth.
- Move GitHub Issues guidance into a new .kilo/skills/gh-issues/SKILL.md so it
loads only when needed.
- Collapse duplicated kilocode_change marker examples in root AGENTS.md to a
brief summary plus pointer to the kilocode-merge-minimizer skill.
Replaces the plugin approach with a narrow conditional at the single call
site in session/llm.ts where maxOutputTokens is passed to chat.params.
No new file, no new test file, one kilocode_change block.
* refactor(vscode): replace collapsible diff summary with clickable banner
Replace the expandable accordion-based diff summary in session turns
with a simpler clickable button that opens the dedicated changes view
via a postMessage to the extension host. This removes the inline file
list expansion in favor of the native VS Code changes panel.
- Remove Collapsible/Accordion/StickyAccordionHeader components
- Remove getDirectory/getFilename helpers and expanded state management
- Add openChanges action via useVSCode context
- Style the trigger as a minimal button with hover chevron indicator
- Update story name/description to reflect new behavior
* feat(vscode/diff): simplify DiffSource interface to declarative fetch model
Convert DiffSource from a class-based lifecycle pattern (initialFetch/start/dispose)
to a minimal declarative interface where sources only implement `fetch()` and
optionally `fetchFile`/`revert`/`dispose`. Move all polling, hash-dedup, loading
state, and message posting responsibility into SourceController.
- Replace class-based SessionDiffSource/WorktreeDiffSource with factory functions
- Introduce DiffSourceFetch return type with stopPolling flag for terminal states
- Remove DiffSourcePost/DiffSourceMessage types in favor of controller-owned posting
- SourceController now owns setInterval polling and hash-based dedup logic
- Rename requestFile → fetchFile, revertFile → revert, make dispose optional
- Update all unit tests to match the new declarative source contract
* refactor(vscode): add per-turn diff viewing with hidden picker mode
Introduce a TurnDiffSource that fetches diffs scoped to a single user
message rather than the full session snapshot. The diff viewer can now
open in a fixed, non-switchable mode when invoked from a specific turn.
- Add `turn.ts` source with factory, descriptor, and id helpers
- Extend PanelContext with `hidePicker` flag to suppress source selector
- Thread `turnId` from webview message through sidebar handler to command
- Catalog returns empty descriptors when picker is hidden
- Export `toSessionDiffFile` from session source for reuse in turn source
- Add `turn` to DiffSourceType union
- Add unit tests for turn source fetch behavior and catalog integration
* fix(vscode/diff): always log DiffSource fetch errors
Initial-fetch errors were only posted as a discarded 'error' message and
had no console trace, making them invisible in production. Log on both
initial and polling ticks so Extension Host output captures the failure.
* chore: update kilo-vscode visual regression baselines
* feat(vscode/diff): self-cancel polling when source reports completion
Convert polling callback to async and use runFetch return value to
stop the interval once the diff source signals it is done, avoiding
unnecessary continued fetches after completion.
---------
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
* fix(vscode): distinguish timeout from user cancellation in commit message generation
Closes#8366Fixes#8366 — extension process crash (silent failure) when clicking
"Generate Commit Message".
Two bugs existed in the commit message generation service:
1. When the 35-second client-side timeout fired, the error handler
silently swallowed it — the spinner disappeared with no feedback,
which users perceived as a crash.
2. Two tests ("uses the matching repository when SourceControl arg is
provided" and "falls back to first repository when SourceControl arg
has no match") passed {} as the VS Code cancellation token mock,
causing token.onCancellationRequested is not a function to throw.
In index.ts, the single controller.signal.aborted check conflated user
cancellation and timeout. Replaced with two explicit flags (userCancelled,
timedOut) set in their respective abort callbacks:
- User cancels: silent (they know)
- 35s timeout: shows "Commit message generation timed out. Please try again."
- Server/network error: shows the error message as before
In index.spec.ts, the two affected test mocks now pass
{ onCancellationRequested: vi.fn() } instead of {} so the production
code path executes correctly.
| before | after |
| ------ | ----- |
| Spinner disappears silently on timeout | "Commit message generation timed out. Please try again." shown |
1. Open a git repository in VS Code with the Kilo Code extension
2. Go to the Source Control panel
3. Click the Kilo "Generate Commit Message" button
4. Disconnect the Kilo backend and wait 35s — you should now see
"Commit message generation timed out. Please try again." instead of
a silent spinner disappearance
5. Click cancel -> should dismiss silently as before
Unit tests: npx vitest run src/services/commit-message/__tests__/index.spec.ts
-> 11/11 pass
Discord: sanan9
* fix(vscode): improve Enhance Prompt quota error guidance
Map provider quota/billing retry failures to an actionable user-facing message for Enhance Prompt and preserve the raw provider response in the details string.
Also adds targeted unit tests for quota and non-quota normalization behavior.
Refs #9464
* fix(vscode): make enhance prompt quota messaging generic
* test(vscode): update enhance prompt quota wording expectation
gpt-5 models rejected via openai-compatible proxies (e.g. LiteLLM) because
the SDK emits max_tokens while OpenAI requires max_completion_tokens and
the compatible SDK cannot rename the field. Clear the cap so the upstream
default output budget applies.
* feat(agent-manager): add searchable tabs menu
* test(agent-manager): include current tabs menu classes
* style(agent-manager): format tabs menu files
* fix(agent-manager): avoid class-like behavior hook
Add a clickable hint at the bottom of the autocomplete settings
that navigates to the Models tab so users can find where to choose
the autocomplete model. Bump KiloProvider max-lines to 3430.
* fix(vscode): restore inline tool diffs
* fix(vscode): render tool patches in kilo ui
* style: format long regex assignments and add change marker comment
Reformat multi-line regex match assignments in kilo-ui-contract test
to satisfy line length limits, and annotate the `contents(diff)` call
in session-diff with a kilocode_change tracking comment.
* fix(kilo-vscode): append trailing newlines to expected diff content assertions
Update test expectations in diff-session-source to include trailing
newlines in before/after content, matching actual file content behavior.
* fix(vscode): guard empty-patch diffs in session turn accordion
Match diff-session-source.ts:99 behavior by short-circuiting contents()
when the patch is empty (binary or summarized files), so the accordion
content stays empty instead of rendering a confusing whitespace-only
diff.
---------
Co-authored-by: Imanol Maiztegui <imanol.mzd@gmail.com>
Upstream 2283979199 (Preapprove agent tmp directory access) extended the
agent.ts whitelistedDirs with Global.Path.tmp/*, and the new v1.14.33 test
asserts tmp/agent-work -> allow on the explore agent. Kilo's patchAgents
replaces the whole explore permission and had only Truncate.GLOB in its
external_directory block, so both /some/other/path (expected ask) and
tmp/agent-work (expected allow) resolved to deny via the outer '*':'deny'
catch-all (findLast picks it over any defaults external_directory rule).
Commit d2e21c5006 tried to fix this by dropping the '*':'ask' on the
assumption that defaults already provided it — that rationale was wrong,
since defaults' rules come before the patch's catch-all in the merged
ruleset. Mirror upstream's inline shape instead: thread whitelistedDirs
through to patchAgents and rebuild the explore external_directory as
{ '*':'ask', ...whitelistedDirs -> 'allow' }, matching what upstream's
explore does natively.
Upstream's v1.14.33 test asserts Instance.current throws during Effect init
(ALS not installed around init). Commit d2e21c5006 intentionally inverts
that: Kilo wraps init in the Instance ALS so KilocodeBootstrap — and the
KiloIndexing.init that it forkDetaches — can read Instance.directory.
Rewrite the test to assert Kilo's contract instead of restoring upstream
behaviour.
Walks through what the thumbs up/down feature does in both the VS Code
extension and the CLI/TUI, why ratings matter, exactly what gets sent
when a user rates a response, and how to disable it via VS Code's
telemetry setting or KILO_TELEMETRY_LEVEL. Privacy claims are scoped
to the rating event itself; broader telemetry questions defer to
PRIVACY.md.
Linked from the Productivity Tools group in the Code With AI nav,
between Voice Transcription and the Agent Behavior subsection.
The previous `watchTelemetryState` fix updated the webview UI in real
time but left the CLI subprocess's PostHog client stuck on its
spawn-time `KILO_TELEMETRY_LEVEL` value. A user who started VS Code
with telemetry off and toggled it on at runtime saw the thumbs UI
appear (good) but every webview event was silently dropped at the
CLI's `Client.capture()` gate (bad).
Add a runtime sync channel:
- New `POST /telemetry/setEnabled` Hono route on the CLI server that
calls `Telemetry.setEnabled(enabled)` to flip the `posthog-node`
client's opt state.
- New `TelemetryProxy.setEnabled(enabled)` method that POSTs to it,
using the same fire-and-forget pattern as `capture`.
- Extension calls `telemetry.setEnabled(vscode.env.isTelemetryEnabled)`
immediately after `telemetry.configure(...)` on every `connected`
state change, so a freshly-spawned CLI gets corrected even when its
spawn-time env var is stale.
- Extension subscribes to `vscode.env.onDidChangeTelemetryEnabled` to
forward runtime consent changes to the CLI as they happen.
All three changes live in Kilo-owned files (the route is already a
`kilocode_change - new file`, and the extension is Kilo-only). Zero
upstream OpenCode merge surface.
Closes#9872 fully (the previous `d67c5e307c` covered only the webview
UI).
The kilo-ui Icon was capturing the registry lookup into a non-reactive
const at component setup, so callers that flip the icon prop (e.g.
toggling between thumbs-up and thumbs-up-filled when a feedback rating
changes) saw the SVG content stay frozen on the original icon.
Fix by reading local.name directly inside the JSX expressions so Solid
re-evaluates viewBox and innerHTML when the prop updates. Matches the
upstream Icon pattern.
Also rename the local 'def' temp to 'icon' as part of the inline
refactor — clearer alongside the 'icons' registry.
Addresses review feedback: Kilo-specific additions belong in Kilo-owned
packages so the diff against upstream OpenCode stays minimal.
- Icons: move thumbs-up/-down/-up-filled/-down-filled paths from
packages/ui/src/components/icon.tsx into packages/kilo-ui's icon
registry. Extend the kilo-ui Icon registry to carry per-icon viewBox
(Heroicons thumbs are 20x20; existing Kilo icons are 16x16). Replace
packages/kilo-ui/src/components/icon-button.tsx (previously a re-export
of @opencode-ai/ui/icon-button) with a local implementation that
uses the kilo-ui Icon so the new names resolve.
- i18n: move the three feedback strings (helpful, notHelpful,
clearRating) from each of 19 packages/ui/src/i18n/<locale>.ts files
into the corresponding packages/kilo-i18n/src/<locale>.ts. The
webview's language.tsx already merges kilo-i18n on top of upstream,
so the runtime keys remain available.
- TUI: extract submitFeedback from
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx into a
new Kilo-owned helper at
packages/opencode/src/kilocode/cli/cmd/tui/feedback.ts. The session
route now imports and invokes it, passing { toast, session, messages }.
Also tightens the Kilo Gateway gate from startsWith("kilo") to
=== "kilo" to match the equivalent fix in the webview.
`isKiloGateway` used `startsWith("kilo")` which matches fictional
aliases like `kilo-dev`/`kilocloud`. The only real gateway provider
ID in the codebase is plain `kilo` — every other usage of it checks
`providerID === "kilo"`. Tighten to an exact match and drop the
`isKiloGateway` tests (it is now a one-line equality check) along
with the fabricated alias case in `buildFeedbackProperties`.
VS Code exposes `env.onDidChangeTelemetryEnabled` for runtime changes
to the telemetry consent setting. The extension was only reading
`env.isTelemetryEnabled` once during `syncWebviewState`, so toggling
`telemetry.telemetryLevel` while a Kilo webview was open left the
feedback UI stuck on its previous visibility state until reload.
Add `watchTelemetryState()` next to `pushTelemetryState()` and wire
the disposable in `setupWebviewMessageHandler` alongside the existing
`watchAutocompleteConfig`. Uses the same registration/dispose pattern
as the autocomplete config watcher.
Also bump the ESLint `max-lines` cap on AgentManagerApp.tsx from 3200
to 3210 to accommodate the FeedbackProvider wrapper that sits inside
the provider chain (past precedent: 3100 → 3200 for terminal tabs).
Closes#9872.
- Replace the fractional hand-drawn thumbs paths with Heroicons 20
outline (default / rated=false) and solid (filled / rated=true).
- Add a CSS rule under assistant-copy-wrapper so hovering the outline
button fills it with currentColor, giving a preview of the rated
state before the user commits.
- Replace <leader>+ with <leader>= in messages_feedback_up: the TUI
parser normalizes <leader> to 'leader+' and splits on '+', producing
an empty key name for '<leader>+' so the binding never fires. The
= key sits on the same physical key as + on most layouts, pairs
visually with <leader>-, and parses to a real key name.
- Wrap StoryProviders with FeedbackProvider so stories that render
VscodeSessionTurn (e.g. Diff Summary Collapsed) don't throw
'useFeedback must be used within a FeedbackProvider' under
Storybook visual regression.
- Sync changeset and docs page to mention the new keybind.
Adds thumbs up/down buttons next to the copy button on every assistant
message in the VS Code sidebar, and <leader>+/<leader>- keybinds in the
TUI. UI state is in-memory only — ratings reset on reload / session
switch. Persistence can be added later without changing the telemetry
contract.
Events are sent to PostHog via the existing telemetry pipeline. For
Kilo Gateway turns the payload includes session and message IDs so
feedback can be correlated against gateway logs; for direct providers
those IDs are omitted since we cannot correlate them to upstream data.
`harbor run` (jobs.py) only exposes `--agent-setup-timeout-multiplier`;
the absolute `--agent-setup-timeout` flag only exists on `harbor trials`.
Use the multiplier (2.0 = 720s from the 360s default) instead.
Both tests rely on JS-level spies that the upstream Workspace refactor bypasses:
1. spyOn(globalThis, "fetch") doesn't intercept anymore. The Effect FetchHttpClient layer holds fetch as a fiber-ref with defaultValue: () => globalThis.fetch, captured at fiber start. The spy descriptor isn't observed through that ref — calls go to the original fetch and produce Transport errors against workspace.test.
2. spyOn(SyncEvent, "replayAll") spies the module-level wrapper. Upstream's Workspace.Service now yields SyncEvent.Service inside the layer and calls sync.replayAll(events) on the Service directly, never touching the module-level export.
Restoring coverage requires injecting Effect-side mock layers (custom HttpClient + SyncEvent.Service). Out of scope for the merge resolution. Tracked for follow-up.
Two structural divergences make the upstream-added parity test unrunnable on Kilo:
1. Effect's HttpApi runtime emits 'field: null' for Schema.optional() values when the source data has the property as undefined. Hono uses JSON.stringify which omits undefined keys. Kilo-specific Model fields (ai_sdk_provider, prompt, recommendedIndex, isFree) and Command fields (agent, model, subtask) all hit this.
2. Reading /config twice in sequence (legacy then httpapi) returns different defaults as Kilo's ConfigService cache mutates between calls.
The test is upstream-added; opencode's schema doesn't carry these extra fields, so it doesn't trip the divergence. Skip until either Kilo migrates the affected schemas to NullOr (changing the public surface) or the parity test learns to ignore Kilo-specific fields.
- InstanceStore: run Instance.provide init inside the ALS context so KilocodeBootstrap (and any forkDetach work it spawns like KiloIndexing.init) can read Instance.directory. Upstream refactor moved init out of the ALS scope; kilo-main's pre-merge Instance.provide wrapped it. Without this, KiloIndexing.init silently fails with "No context found for instance".
- kilocode/agent: thread worktree through planGuard/patchAgents instead of reading Instance.worktree at agent state construction time. Agent state is built inside Effect (no ALS) via InstanceState.make — reading the ALS-backed Instance.worktree there crashed under the new architecture.
- kilocode/agent: drop the "*": "ask" from explore external_directory — defaults already provides it, and redefining here overwrites the tmp/skill allowlist via findLast().
- test/server/httpapi-instance.test.ts: revert the ported Hono-bridge tests. Upstream put the same tests in httpapi-instance.legacy.test.ts (renamed file); the port duplicated them.
- test/server/httpapi-instance.legacy.test.ts: mark the catalog test test.skip with Kilo's original rationale (/agent 500s via the bridge; the bridge is not enabled in any production client).
- test/server/httpapi-ui.test.ts: delete. Tests upstream's proxy-to-app.opencode.ai fallback that Kilo intentionally removed (src/server/routes/ui.ts kilocode_change).
- test/server/httpapi-raw-route-auth.test.ts: basic("opencode", ...) → basic("kilo", ...) to match the Kilo username default.
- test/provider/models.test.ts: skip describe block. Upstream tests assert raw-fixture passthrough but Kilo's ModelsDev.get() filters/injects providers based on Config.get(), which needs an Instance context the test doesn't provide.
Auto-merge from v1.14.33 produced duplicate "rotating-file-stream" entries in packages/core/package.json (both kilo-main and upstream added the same dependency in the same release window). bun install fails fast on duplicate keys, breaking CI setup. Drop the redundant entry and refresh bun.lock.
Replace 'as SessionPrompt.PromptInput' with 'as unknown as SessionPrompt.PromptInput' to match the pre-existing pattern in the legacy Hono handler (instance/session.ts:901,936). The single cast was rejected by TypeScript because the schema-derived ctx.payload has readonly arrays while Kilo's PromptInput override declares parts as mutable PartInputUnion[]. The double cast is the established Kilo workaround for this readonly→mutable mismatch and keeps the Kilo diff vs upstream minimal.
Mechanical follow-up to the v1.14.33 merge:
- src/server/routes/ui.ts: remove dead proxy fallback (proxy/createHash/csp were intentionally commented out by Kilo; the Effect/Promise paths still referenced them)
- src/kilocode/{plan-followup,session/prompt}.ts: pass Instance.current to Session.plan(input, instance)
- src/server/routes/instance/httpapi/handlers/session.ts: cast PromptPayload spread to PromptInput (readonly→mutable schema/runtime mismatch)
- src/plugin/index.ts: cast external @opencode-ai/plugin auth plugins through unknown to bridge to local @kilocode/plugin types
- script/build.ts: drop duplicate sourcemap key (Kilo's release-aware version wins)
- test/kilocode/indexing-{startup,worktree}.test.ts: switch from Instance.disposeAll/InstanceBootstrap-as-effect to disposeAllInstances/getBootstrapRunEffect
- test/kilocode/model-cache-org.test.ts: convert Instance.provide init from async fn to Effect
- test/kilocode/kilo-loader-auth.test.ts: drop ModelsDev.Data.reset() (no longer exists)
- test/kilocode/plan-exit-detection.test.ts, plan-followup.test.ts: pass Instance.current to Session.plan
- test/kilocode/{plan-followup,session-list}.test.ts: replace Session.list() with AppRuntime.runPromise(Session.Service.use((svc) => svc.list()))
Setting handle.message.finish before the result === "compact" branch broke guardCompactionAttempt (which fills in "error" with ??=) and the overflow detection at compaction.create. Move the default to right before "continue" and gate it on result !== "compact" so the compaction paths see the original undefined value.
The loop reloads messages from storage at the top of each iteration via filterCompactedEffect, so an in-memory mutation on handle.message does not propagate. Persist the defaulted finish via updateMessage so the next iteration's break check actually observes it.
Some Anthropic-compatible providers terminate the response stream with a final message_delta that carries stop_reason: null followed immediately by message_stop. The AI SDK then never sets a finishReason on the assistant message, the prompt loop's break check stays false, and the agent keeps issuing new model calls indefinitely. Default the missing finish to "unknown" so the existing exit condition fires when no tool calls were emitted.
* feat(vscode): add foundational types and abstractions for unified diff panel
Introduce the core type definitions and abstractions that support the
upcoming session diff viewer:
- PanelSurface: testable abstraction over vscode.WebviewPanel
- DiffSource/DiffSourceDescriptor: contracts for swappable diff providers
- DiffSourceCatalog: stub registry for enumerating and constructing sources
- PanelContext/DiffFile: cross-cutting types shared by manager and webview
* feat(diff): implement worktree diff source with polling and file revert
Add WorktreeDiffSource, a DiffSource implementation that computes diffs
between the local working tree and the base branch. Key behaviors:
- Resolves the diff target from the workspace root via GitOps
- Performs an initial fetch then polls every 2.5s with hash-based dedup
- Supports single-file revert through WorktreeDiffClient
- Posts structured messages (loading, diffs) to the panel via DiffSourcePost
* add(vscode): session diff source and unified patch parser
Introduce two new modules under the diff sources layer:
- patch-to-before-after.ts: reconstructs before/after file content
from full-context unified diff patches by filtering line prefixes
- session.ts: SessionDiffSource fetches accumulated diffs for a given
session, converts patches to before/after pairs, and posts results
to the diff panel without polling or SSE
* feat(diff): wire up diff source catalog with session and worktree builders
Replace stub implementations in DiffSourceCatalog with real logic:
- Inject KiloConnectionService and use it to fetch session diffs
- Populate listAvailable based on PanelContext (workspace root, session)
- Route build() to WorktreeDiffSource or SessionDiffSource by id prefix
- Extract sessionDescriptor() and SESSION_PREFIX from SessionDiffSource
to decouple descriptor creation from class instantiation
- Export WORKSPACE_DESCRIPTOR from worktree module for catalog reuse
* refactor(vscode): introduce DiffPanelManager and centralize diff panel lifecycle
Extract panel ownership out of DiffViewerProvider into a new
DiffPanelManager class that manages a single global "Changes" webview.
Key changes:
- Add DiffPanelManager with source-swapping, loading pulse, webview
serialization, and disposable lifecycle management
- Add testable Scheduler abstraction to decouple setTimeout usage
- Extend DiffSourceCatalog with defaultSourceId() resolution logic
and replace magic "workspace" string with WORKSPACE_SOURCE_ID const
- Extract sessionSourceId() helper in session source module
- Thread sessionId through openChanges command and sidebar context so
the panel can open directly to the relevant session diff
- Re-register webview panel serializer under DiffPanelManager.viewType
* feat(diff): add source descriptor and capability message types for webview
Introduce new extension-to-webview and webview-to-extension message
interfaces to support multi-source diff panel switching:
- DiffSourceCapabilities, DiffSourceDescriptor for describing available
diff sources with revert/comments flags and grouping metadata
- SetAvailableSourcesMessage and DiffViewerCapabilitiesMessage for
pushing source lists and active capabilities to the webview
- SelectSourceRequest for the webview to request a source switch
* refactor(webview): integrate diff source picker into viewer and relocate shared types
Move DiffSourceCapabilities and DiffSourceDescriptor interfaces out of
extension-messages.ts into the shared diff/sources/types module, and
re-export them via import. Add DiffPickerHeader component with a
grouped Select dropdown for switching between multiple diff sources.
Wire source selection state and capability tracking into DiffViewerApp,
handling setAvailableSources and diffViewer.capabilities messages and
conditionally rendering the picker header above the diff view.
* feat(diff-viewer): add canRevert and canComment capability flags to full-screen diff
Introduce two optional boolean props (`canRevert`, `canComment`) on
FullScreenDiffView that allow callers to disable revert actions and
comment creation based on the active diff source's capabilities.
Guard gutter click handlers, keyboard shortcuts, the "Send all" button,
revert buttons, and sidebar revert callbacks behind these flags. In
DiffViewerApp, forward the capability values from the selected source
and reset transient UI state (comments, diff style, reverting set) on
source switches via a reactive effect.
* test(vscode): add unit tests for diff panel manager, source catalog, and patch utilities
Cover DiffPanelManager lifecycle (open, reveal, dispose, deserialized
panel disposal, source switching, comment forwarding), DiffSourceCatalog
listing/defaulting/building logic, SessionDiffSource fetch-and-convert
flow, and patchToBeforeAfter edge cases.
Also refactor DiffPanelManager to decouple panel creation from surface
adoption: the createSurface factory no longer receives a panel argument,
panel construction moves into a private defaultCreateSurface method, and
deserializePanel now disposes stale panels instead of rewiring them.
Extend the vscode mock with a createOutputChannel stub to support the
new test harness.
* refactor(diff): extract command-context assembly into DiffPanelManager.openFromCommand
Move PanelContext construction (workspace root resolution, session ID
lookup, initial source selection) out of the extension command handler
and into a dedicated openFromCommand method on DiffPanelManager. This
eliminates the extension's direct dependency on getWorkspaceRoot and
provider.getCurrentSessionId by accepting a sessionIdProvider callback
through DiffPanelManagerOptions.
Update tests to cover both provider-based and arg-based session ID
resolution paths in openFromCommand.
* feat(vscode): unify changes panel with multi-source diff architecture
Delete the legacy DiffViewerProvider in favor of the new
DiffPanelManager-based architecture. Decompose review-utils into
focused modules under diff/shared/ (client, hash, target) and update
all consumers to import from the new locations.
- Remove DiffViewerProvider and its registration in extension.ts
- Extract WorktreeDiffClient, DiffTarget into diff/shared/client
- Extract hashFileDiffs into diff/shared/hash
- Extract resolveLocalDiffTarget into diff/shared/target
- Slim down review-utils to only VS Code UI helpers
- Add changeset for the unified Changes panel feature
BREAKING CHANGE: DiffViewerProvider is removed; all diff viewing now routes through DiffPanelManager
* refactor(diff): add polling with hash dedup to SessionDiffSource
Upgrade SessionDiffSource from one-shot fetch to periodic polling
(2.5s interval) with hash-based deduplication, matching the pattern
already used by WorktreeDiffSource. Also clean up legacy references
in WorktreeDiffSource doc comments.
- Introduce POLL_INTERVAL_MS constant and start/stop polling lifecycle
- Track lastHash to skip redundant diff posts when content unchanged
- Extract fetchDiffs helper to share between initialFetch and poll
- Guard all post calls against disposed state
- Add comprehensive polling unit tests with scripted fetch helper
* fix(ui): rename worktreeStats() calls to session.summary() in ChatView
Update ChatView component to use the renamed `session.summary()`
accessor instead of the deprecated `session.worktreeStats()` method,
aligning with the unified multi-source diff architecture.
* feat(diff): add snapshots-disabled notice to session diff source
Introduce a `notice` message type in the diff source protocol so that
`SessionDiffSource` can warn users when snapshot tracking is turned off
for their repository. The check queries the workspace config before
fetching diffs; when disabled, polling is skipped entirely and a
warning banner is rendered in the diff viewer webview.
- Add `SnapshotEnabledCheck` callback wired through `DiffSourceCatalog`
- Extend `DiffSourceMessage` and `ExtensionMessage` with `notice` type
- Forward notice messages from `DiffPanelManager` to the webview
- Render warning banner with icon in `DiffViewerApp`
- Add CSS for `.diff-viewer-notice` component
- Cover new behavior with unit tests
* refactor(i18n): replace hardcoded notice strings with typed keys and localized messages
Convert the diff viewer notice system from passing raw English strings
through the message protocol to using well-known typed identifiers that
the webview resolves to translated text at render time.
- Define `DiffSourceNotice` union type in source protocol layer
- Define `DiffViewerNotice` union type in webview message contract
- Change `notice` field from `message: string` to `notice: T | undefined`
- Map notice identifiers to i18n keys in `DiffViewerApp` via lookup table
- Localize `DiffPickerHeader` labels and group names through `useLanguage`
- Add `diffViewer.*` translation keys across all 19 locale files
- Update unit tests to assert typed notice identifiers
* docs(changeset): update unified diff panel description
Clarify feature summary to mention sidebar badge counts and
snapshots-disabled warning alongside the source dropdown.
* feat(vscode): port markdown diff render ahead of main merge
Cherry-picks the user-facing bits of main's #9846 (render markdown diffs) into
this branch so merging main later is trivial for the 5 shared files. Wires the
markdown toggle through the new DiffPanelManager architecture as global state,
persisted via the kilo-code.new.diff.renderMarkdown setting.
* refactor(vscode): replace if-chain message dispatch with handler map
Extract DiffPanelManager.onMessage logic into a declarative
messageHandlers record and a dedicated onWebviewReady method.
Also fix import paths for DiffSourceDescriptor/DiffSourceCapabilities
to reference canonical source types, add explicit generic to Set<string>,
and extend webview tsconfig include to cover diff-viewer and diff-virtual.
* style(ui): add padding to select section headers
* fix: formatting
* fix(vscode): prevent stale source activation after panel teardown
Introduce an epoch counter to guard against race conditions where
activateSource completes its async initialFetch after the panel has
been disposed or the source has been swapped. The epoch is incremented
on every source teardown and checked before starting polling.
* refactor(vscode): scope source post guard to lifecycle epoch
Pass the epoch counter into createSourcePost so that messages emitted
by a source after its lifecycle has ended are silently dropped. This
closes a gap where polling callbacks could still push updates to the
surface after the source was swapped out.
* feat(diff-viewer): rename workspace source to "Local Changes" and add tooltip
Remove the "Workspace" source group, moving the worktree source under
"Git". Rename its label from "Workspace local" to "Local Changes" across
all locales and introduce a tooltip explaining that it covers all branch
changes vs the base (uncommitted files and local commits). The picker
header now renders option tooltips on hover with a delayed open.
* docs(i18n): translate workspace tooltip into all supported locales
Replace the English fallback string for
`diffViewer.source.workspace.tooltip` with native translations in ar,
bs, ja, ko, no, pl, ru, th, tr, uk, zh, and zht locale files.
* style(diff-viewer): rename parameter `d` to `desc` in DiffPickerHeader
Improve readability by expanding the terse single-letter parameter name
to a more descriptive `desc` across helper functions and the render
callback in DiffPickerHeader.
* refactor(diff-sources): replace hardcoded label with type-driven i18n key lookup
Replace the `label` string field in DiffSourceDescriptor with a
`DiffSourceType` discriminant (`"workspace" | "session"`). The webview
now composes i18n keys dynamically from the type, eliminating ad-hoc
id-matching logic in DiffPickerHeader and ensuring every source gets
both a label and a tooltip via the translation dictionaries.
Also adds `diffViewer.source.session.tooltip` translations for all
supported locales and introduces descriptor-type stability tests.
* fix(i18n): shorten session source label by removing "current" qualifier across all locales
* refactor(diff): extract shared polling interval constant into dedicated module
Consolidate the duplicated `POLL_INTERVAL_MS` definitions from
`session.ts`, `worktree.ts`, and the hardcoded literal in
`worktree-diff-controller.ts` into a single `DIFF_POLL_INTERVAL_MS`
export in `diff/polling.ts`. Update all consumers and tests to
reference the new canonical constant.
* feat(diff): replace DiffPanelManager with DiffViewerProvider and SourceController
Remove the `manager/` directory (DiffPanelManager, panel-surface,
scheduler) and introduce two focused replacements:
- `DiffViewerProvider`: owns the webview panel lifecycle, HTML rendering,
and message routing directly against `vscode.WebviewPanel`
- `SourceController`: manages the active DiffSource with epoch-based
stale-message filtering, decoupled from any webview abstraction
The PanelSurface and Scheduler indirection layers are eliminated in
favor of direct VS Code API usage in the provider and a simpler
epoch-guarded post function in the controller. Tests are rewritten
to exercise SourceController in isolation without fake surfaces.
BREAKING CHANGE: DiffPanelManager, PanelSurface, and Scheduler exports are removed
* refactor(diff): decouple SourceController from DiffSourceCatalog via dependency injection
Replace the direct DiffSourceCatalog dependency in SourceController with
two injected function callbacks (`build` and `listAvailable`), removing
the tight coupling to the catalog class. DiffViewerProvider now passes
thin wrappers that delegate to the catalog instance.
Update tests to use lightweight inline fakes instead of the FakeCatalog
subclass, and remove redundant polling/lifecycle tests that tested
implementation details rather than behavior.
* feat(diff): add lazy per-file content loading for worktree diffs
Introduce on-demand fetching of full file content (before/after) for
summarized diff entries. The worktree source now polls only a lightweight
summary and resolves detail via `requestFile` when the webview expands a
file.
- Add `requestFile` to `DiffSource` interface and implement in
`WorktreeDiffSource` using local git operations
- Wire `diffViewer.requestFile` message through DiffViewerProvider to
SourceController
- Add `diffViewer.diffFile` extension message to deliver single-file
detail back to the webview
- Webview merges incoming summaries with cached detail, tracks
per-file loading state, and auto-refreshes stale entries
* refactor(session): replace custom patch parser with shared kilo-ui session-diff utilities
Remove the hand-rolled `patchToBeforeAfter` function and its unit tests
in favor of the `normalize` and `text` helpers exported from
`@kilocode/kilo-ui/session-diff`. This eliminates duplicated parsing
logic and aligns the extension with the canonical diff reconstruction
used across the UI layer.
* test(diff): add hash utility tests and remove obsolete polling specs
Introduce a dedicated test suite for `hashFileDiffs` covering stability,
field sensitivity, and summarized-patch exclusion semantics. Remove the
now-unused polling tests and their helper functions (`scripted`, `wait`,
`modifiedPatchV2`) from the session source spec, reducing test surface
to match the current implementation boundaries.
* style(webview): add spacing for diff picker header component
* fix(diff): prefer workspace over session as default diff source
Change priority order in defaultSourceId so workspace source takes
precedence over session source when both workspaceRoot and sessionId
are present. Update ChatView to use renamed worktreeStats() accessor.
* fix(vscode): correct DiffViewerProvider path, bump max-lines cap, and apply font-size token
Update font-size arch test to reflect DiffViewerProvider's move into
src/diff/, raise KiloProvider max-lines eslint cap to 3500, and
replace hardcoded 12px in banners.css with --kilo-font-size-12.
Update `findLatestCompatCommit` to use semantic versioning when identifying the latest compatibility commit. This ensures the correct commit is selected even when upstream tags diverge or are not strictly linear.
- Add semver parsing and comparison utilities
- Implement `targetSemver` to resolve versions from tags or commit messages
- Filter and sort compatibility candidates by version relative to the target version
- Add test case for diverging upstream tags
Remove the `.kilo-diff-theme` utility class and its dedicated stylesheet,
relocating all Pierre diff engine custom properties into the centralized
`vscode-bridge.css` theme definition. This allows diff components to
inherit theming from the document root without requiring an explicit
class annotation on each container element.
- Delete `webview-ui/src/styles/diff.css`
- Drop `kilo-diff-theme` class from DiffPanel, FullScreenDiffView,
DiffVirtualApp, and PermissionDiff components
- Remove corresponding `@import` statements from chat.css and
agent-manager.css
Hardcodes the list of active and disabled workflows and fails CI when
.github/workflows/ drifts. Wired into check-opencode-annotations so we
don't add a new workflow file for this.
The hello-world smoke test occasionally hits Harbor's 360s
AgentSetupTimeoutError when an apt mirror or NodeSource cdn is slow on
the Blacksmith runner, even though the install normally finishes in
~2:23. Bump the cap to 600s and start uploading the install script's
stdout/stderr so we can pinpoint the stalling step next time.
The HttpApi authorization middleware defaulted the username to
"opencode", while the Hono AuthMiddleware already defaulted to "kilo"
(kilocode_change). The parity tests added by upstream in
packages/opencode/test/server/httpapi-sdk.test.ts exposed the
inconsistency. Align the HttpApi middleware to also default to "kilo"
and update the pre-existing basic-auth test creds that hit it.
Two new httpapi-sdk parity tests also hit Kilo overlay routes
(/config/providers, /agent) that aren't yet wired onto the Effect
HttpApi bridge, returning 500. Skip those two with kilocode_change
markers pointing at the same "migrate Kilo overlay routes onto the
HttpApi bridge" follow-up the existing httpapi-bridge.test.ts comment
references.
Covers the "Node.js 20 is deprecated" warning emitted by actions/checkout,
actions/setup-node, actions/cache, actions/upload-artifact and
actions/download-artifact on their older releases.
Every bumped line carries an inline `# kilocode_change` marker since these
workflow files are shared with upstream OpenCode. When upstream bumps its
own action versions we just drop the markers on merge.
Keeps the 4vcpu host change in test.yml (already annotated with
# kilocode_change). The Node 20 deprecation warning stays for now;
`FORCE_JAVASCRIPT_ACTIONS_TO_NODE24=true` already forces the v4 actions to
Node 24 at runtime, so the warning is informational and CI still works.
Bumping all actions would require 40+ kilocode_change markers across
shared upstream workflows and invite conflicts on every upstream merge —
we'll pick up the version bumps when upstream does.
- Bump all active workflows to action versions that natively target Node 24:
checkout@v6, setup-node@v6, cache@v5, upload-artifact@v7, download-artifact@v8.
Resolves the "Node.js 20 is deprecated" warning in CI logs. The kept
`FORCE_JAVASCRIPT_ACTIONS_TO_NODE24` env stays as a no-op safety net (also
in upstream OpenCode).
- test-runner: when running under GitHub Actions, emit a `::warning::`
annotation per flaky file and append a markdown table to
`$GITHUB_STEP_SUMMARY`. mikepenz/action-junit-report already surfaces
failures from the JUnit XML, but flakies pass cleanly on retry and were
invisible in the UI.
The per-file JUnit merge was walking `<testsuite>` tags by hand and closing
on the first `</testsuite>` it found. Bun's junit reporter nests one
`<testsuite>` per `describe` block inside an outer `<testsuite>` for the
file itself, so the inner close was matched and the outer one got dropped.
Every file contributed one unclosed `<testsuite>` to the merged output,
pushing XML depth up until mikepenz/action-junit-report's sax parser
failed with "Unexpected close tag" (and xmllint with "Excessive depth").
Switch to grabbing everything between the outer `<testsuites ...>` and
`</testsuites>` of each file's XML — nested structure is preserved
verbatim, no custom walking needed. Read aggregate counts from the root
`<testsuites>` attributes so nested `tests="..."` attrs don't get
double-counted either.
Validated locally: `xmllint --noout` passes on the merged output for a
mix of files with and without nested describes.
- Lower default runner concurrency from `os.cpus().length` to `min(4, cpus)`.
The bottleneck in CI is shared resources (OAuth callback ports, global
filesystem like `~/.local/share/kilo`), not CPU, so eight parallel Bun
processes were triggering port/FS races instead of going faster.
- Raise per-test timeout from 30s to 60s. Slow `spawn` on Windows was
tripping the 30s limit on tests that were just slow, not broken
(e.g. `session/prompt.test.ts` at ~86s, `provider/provider.test.ts` at ~54s).
- Retry failing files once and surface them as FLAKY in the summary plus a
dedicated section. Bugs still fail on every attempt; contention recovers.
- Drop CI runners from 8vcpu to 4vcpu to match upstream OpenCode — with
concurrency capped at 4, the extra cores bought us nothing.
Consolidate workflow disabling: the six workflows previously soft-disabled
via `if: false` / `&& false` are now moved and renamed alongside the
other `.disabled` workflows so the disabling mechanism is consistent.
Reset six workflow files that were soft-disabled via `if: false` / `&& false`
to the last merged upstream (v1.14.29) before moving them to the disabled folder
in a follow-up commit.
jschardet produced labels like "ascii", "gb2312", "MacCyrillic", "IBM855/866",
and "TIS-620". chardet's supported encoding set does not include any of
these (ASCII folds into UTF-8; Chinese is emitted as GB18030), so the
mappings were dead code.
Extract duplicated Pierre diff CSS custom properties from multiple
stylesheets into a single shared `.kilo-diff-theme` class in
`webview-ui/src/styles/diff.css`. Apply the class to all diff container
elements (DiffPanel, FullScreenDiffView, DiffVirtualApp, PermissionDiff)
so hover overrides are consistently defined.
This fixes diff hover styling by adding the missing
`--diffs-bg-addition-hover-override` and
`--diffs-bg-deletion-hover-override` variables and eliminates ~130 lines
of duplicated CSS variable declarations across the codebase.
Result of running find-reset-candidates.ts across the repo and hand-
reviewing each candidate.
- mcp/oauth-provider.ts: kilocode_change markers were stale — the
branding (Kilo, kilo.ai) already lives in the translate transforms,
so the marker annotations no longer point at any Kilo-specific code.
- acp/session.ts: matches upstream's import order.
- tui/ui/dialog.tsx: matches upstream's prettier line-wrap on a long
onMouseUp prop.
No behavior change.
Add a new setup script to configure `merge.conflictStyle=zdiff3` locally
within the repository. This ensures that the common ancestor is visible
during merge conflicts, which is required for structural resolution by
`mergiraf` and simplifies manual conflict resolution.
The configuration is applied during `bun install` via the `postinstall`
hook and remains as a fallback for the upstream merge utilities.
chardet is less aggressive than jschardet on short CJK samples; a
12-byte Shift_JIS phrase now collides with the windows-1252 profile.
Reuse the longer Shift_JIS sample the rest of the suite relies on.
Swap jschardet for the actively-maintained chardet library for text
encoding detection. chardet ships with TypeScript definitions, so the
local jschardet module shim is no longer needed.
Consolidate the UTF-8/16/32 BOM byte literals into a single lookup table
and share a startsWith helper across detection and encoding. Pure
refactor in a Kilo-only file; upstream diff unchanged.
Replace `export namespace Encoding`/`EncodedIO` wrappers with top-level
exports and switch consumers to `import * as Encoding`/`EncodedIO`.
The module itself acts as the namespace, avoiding the TS-namespace
wrapper that tree-shakers and some module resolvers handle awkwardly.
Upstream opencode stamps its own version into shared files (the Zed extension toml + any package.json it bumps), which leaves the tree pointing at an upstream release tag that doesn't exist on Kilo's pipeline — Zed download URLs silently 404 as a result.
script/sync-versions.ts rewrites every top-level package.json version and the Zed extension toml (version + 5 download URLs) to a single target in one shot. Defaults to the root package.json version, accepts an explicit version argument, and skips packages/kilo-jetbrains/ which tracks its own cadence.
Documented in .kilo/command/upstream-manual-merge.md as a dedicated step-10 commit after 'resolve merge conflicts' so version churn stays out of the behavioural merge commit.
Auto-merge left two entries for rotating-file-stream in @opencode-ai/core's
dependencies block. bun install rejected the JSON, failing every CI job
(typecheck, unit tests, visual regression) at the install step.
Fixes hang when running the finder from the repo root without a path
scope. Root cause: upstream-only packages (packages/console, packages/web,
packages/desktop, etc. in config.skipFiles) contain multi-megabyte
media assets that stall concurrent Bun `git show` subprocesses on the
pipe buffer.
Changes:
- Batch upstream blob sizes in one `git cat-file --batch-check`
subprocess before classifying anything. Files with missing upstream
land directly in `upstream-missing`; files > 256 KB land in the new
`too-large` bucket. Only sane-sized survivors get per-file `git show`.
- Filter out files matching the merge config's `keepOurs` and
`skipFiles` globs (.github workflows, translated READMEs, upstream-
only packages, etc.) — these are intentionally preserved or removed
in Kilo and would otherwise pollute the report and tempt incorrect
resets.
Full-repo dry-run now completes in ~2s.
Incorporate lessons from the v1.14.30 merge: explain reasoning before
showing diffs, investigate why Kilo-specific helpers exist before
bypassing them, prefer commenting-out over deletion with kilocode_change
markers, use TODO (not NOTE) for follow-ups, check adjacent files that
structural upstream splits force you to touch, grep for usages before
deleting apparently-unused upstream declarations, and include PR-body
guidance and the 'resolve merge conflicts' commit convention.
Users that hand us BOM-less UTF-16/32 are violating the documented
contract; trust jschardet + iconv.encodingExists and let the result
be whatever it is.
Move the Kilo question-tool boolean adjacent to `const cfg = yield* config.get()`
matching upstream's placement (commit 9d3c81a68, right after `const config = await
Config.get()`). When upstream's version eventually merges in, the two lines land
next to each other and produce a localized textual conflict — instead of silently
coexisting as dead upstream code plus our divergent gating.
Rename `const question = yield* QuestionTool` to `questiontool` (matching our
existing `lsptool`/`suggesttool` pattern) so the `question` identifier is free
for the boolean, aligning exactly with upstream's naming.
Replace the subprocess-based line diff in classifyDrift with an
in-process multiset diff (approxDiff) so concurrent classifications
don't deadlock on big text files like sprite.svg via Bun $.quiet()
pipe-buffer stalls.
Also filter non-code assets (SVG, PNG, fonts, archives, lock files,
etc.) before classification so they don't bloat the report or stress
git subprocesses. Switch kilo-only path excludes to glob pathspecs so
every packages/kilo-*/ and **/kilocode/** dir is excluded without
maintaining a hand list.
Rename the 'whitespace-only' bucket to 'cosmetic-only' — with the
multiset diff it also catches line reordering, so the old label was
misleading.
When autocompleting a file, folder, or special mention via the @ menu
in the chat textarea, insert a single trailing space (unless the next
char is already whitespace) so typing immediately after selection does
not get appended to the path and break attachment parsing.
* fix(cli): restore kilo branding in MCP auth toast and client name
The 'Run: opencode mcp auth' popup / toast and the MCP protocol client
'name' field were reverted to 'opencode' by an upstream refactor
(opencode PR #22913, pulled in via Kilo PR #9346). Re-apply the
Kilo-branded strings with narrow kilocode_change markers and add a
regression test in packages/opencode/test/kilocode/ so the next upstream
merge fails a Kilo-owned test instead of shipping an 'opencode' popup.
* fix: use kilocode_change block markers for startAuth signature
---------
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Co-authored-by: marius-kilocode <marius@kilocode.ai>
Bulk-finds files that have drifted insignificantly from the last merged
upstream and (optionally) resets them. Extracts shared clean/changed
marker helpers into utils/markers.ts and shared reset logic into
utils/reset.ts so both the single-file reset helper and the new finder
use the same classification pipeline.
Inline question/plan/e2e gating expressions at call sites in the shared
tool registry instead of routing them through KiloToolRegistry. These are
overrides of upstream tool gating — hiding them behind extracted predicates
accepts upstream textual merges cleanly but silently drops Kilo's intent
when upstream restructures the gating. Inlining forces a textual conflict
when upstream touches the same logic, which is the review step we want.
Additive extractions (build/infos/extra) stay in KiloToolRegistry — those
don't have an upstream peer to conflict with.
Also tighten the kilocode_change markers around the Effect.all and return
blocks to per-line markers so unrelated upstream edits don't land inside
Kilo-owned scope.
Add .github/TEAM_MEMBERS and other files Kilo has deleted to skipFiles
so future upstream merges auto-remove them via git rm instead of
surfacing delete-by-us conflicts that need manual resolution.
Also drop the stale github/.gitignore entry from keepOurs (the file
does not exist in Kilo main; keepOurs was a no-op) and move it to
skipFiles so upstream's copy is dropped on merge instead of added.
* fix(cli): serialize OAuth callback port tests
* fix(cli): close MCP OAuth browser test listener race
The mock subprocess emitted its error via setTimeout(10ms), which raced the error listener attachment on slow Windows CI and left BrowserOpenFailed unpublished. Emit on newListener('error') via a microtask so the listener is always attached first. Revert the unrelated test-runner serialization.
* fix(cli): deliver MCP OAuth mock error to listener directly
Override subprocess.on in the mock so the error is queued to the registered listener as soon as it attaches. The previous newListener + emit chain still lost events on slow Windows CI because EventEmitter dispatch can race microtask draining.
The upstream build script tries to bundle packages/app/ which was removed in #9845. Guard the embed step so the CLI build still works, and revert the --skip-embed-web-ui workaround from #9885 since it is no longer needed.
Default NODE_USE_SYSTEM_CA=1 on the spawned CLI so users behind
corporate MITM proxies don't fail device-auth with TLS errors. Add a
kilo-code.new.extraCaCerts setting for custom PEM bundles and honor
VS Code's http.proxyStrictSSL=false as an opt-out.
The nullish coalescing operator (??) treats null as a falsy value and
falls through to the right-hand operand. Switch to a strict undefined
check so that a null assignment on `steps` is forwarded as-is, allowing
callers to express an intentional reset of the steps configuration.
The test file could not load on main — its 'MockTextDocument' import
pointed at a module that no longer exists, so vitest skipped the whole
suite with an 'unhandled error between tests'. The assertions inside
had therefore been vacuous for a while.
The previous commit in this PR updated constructor calls so the file
still typechecked, but the FIM assertions still target the old
AutocompleteModel.generateFimResponse shape and would not exercise the
new generateFim path even if the suite ran. Rather than port 50+
assertions to a mock surface no one has maintained, delete the file.
Fresh coverage can be added against generateFim directly if needed.
Resolve conflicts after main's config.ts refactor to @effect/schema and
the messages.ts → messages/ directory split:
- Port AgentConfig nullable fields + default_agent nullable to the new
packages/opencode/src/config/agent.ts and config.ts Effect schemas.
The null delete sentinel for steps is already preserved by main's
normalize() (steps excluded from spread when undefined).
- Move AgentConfig nullable fields and Config.default_agent nullable to
the new messages/agents.ts and messages/config.ts.
- Re-apply the core fix to ModeEditView.tsx hidden/disable toggles:
send explicit false instead of val || undefined so deepMerge
overwrites a previously-saved true. Keep default_agent clear via
null delete sentinel when hiding/disabling the current default.
- Drop configSaved/configSaveFailed messages; main's retry + optimistic
fallback in KiloProvider and configUpdateFailed + saveError signal in
ConfigProvider subsume the PR's save-outcome split.
Replace nullish coalescing with explicit undefined check so that
`steps: null` is not collapsed to `maxSteps`, preserving the ability
to clear the steps override via a null sentinel value.
Move the initialization of the MCP OAuth callback server from the layer setup to the point where browser authentication is actually required. This prevents unnecessary port binding when authentication is not needed.
Additionally, improve the test runner's XML parsing to correctly handle multiple testsuite attributes and ensure tags are matched accurately.
- Update `packages/opencode/src/mcp/index.ts` to call `McpOAuthCallback.ensureRunning` only upon `UnauthorizedError`.
- Refactor `packages/opencode/script/test-runner.ts` to use a more robust `open` and `sum` logic for test results.
- Add verification to `packages/opencode/test/mcp/oauth-auto-connect.test.ts` to ensure the callback server remains inactive when not needed.
Update the upstream merge script to identify and link to the previous compatibility commit. This ensures that pre-merge transformations maintain a proper commit history by using multiple parents when a prior compatibility base is found, rather than creating disconnected commits.
- Add `findLatestCompatCommit` to locate previous compatibility commits
- Implement `commitTree` and `updateBranch` for low-level git manipulation
- Update `merge.ts` to integrate compatibility base detection and multi-parent commits
The AutocompleteModel class was a thin wrapper around one real function
(generateFimResponse) plus two getters that just deferred to the
autocomplete-models lookup. Fold it into a module-level generateFim()
helper and have callers hold modelId: string directly.
- New fim.ts exports generateFim() and hasValidCredentials() functions.
- AutocompleteInlineCompletionProvider now holds modelId on its
contextProvider and exposes setModel() / getModelId() to sync config.
- ChatTextAreaAutocomplete calls generateFim() directly with the model
id resolved from config per request.
- AutocompleteContextProvider.model becomes modelId: string.
- Closes the refactor started in issue #6793.
Move the credit-balance probe from AutocompleteModel into its single
caller. The provider now receives KiloConnectionService directly and
owns the balance check used by the 402 backoff recovery path.
* fix(vscode): restore MCP OAuth sign-in from settings UI
- Add Sign in control when MCP status is needs_auth; posts authenticateMcp
to run CLI POST /mcp/{name}/auth/authenticate.
- On SSE mcp.browser.open.failed, open the auth URL via
vscode.env.openExternal (CLI subprocess open() often fails under VS Code).
- Dedupe openExternal when multiple webviews receive the same event.
Fixes UI regression described in GitHub issue #8904.
Made-with: Cursor
* fix(vscode): satisfy ESLint max-lines and complexity for MCP OAuth
- Move MCP connect/disconnect/authenticate and openExternal dedupe to
kilo-provider/mcp-oauth.ts.
- eslint-disable-next-line complexity for the webview message router.
Made-with: Cursor
* fix: restore MCP OAuth sign-in in VS Code
* fix: simplify MCP OAuth callback delegation
* fix: clarify MCP OAuth callback delegation
---------
Co-authored-by: e.olbrych <e.olbrych@mkmc.pl>
Co-authored-by: marius-kilocode <marius@kilocode.ai>
* feat(vscode): add dev launcher preserve settings flag
* fix(vscode): parse dev launcher settings as jsonc
* fix(vscode): keep dev launcher settings merge dependency-free
Both fields were always null and never assigned in production code. The
status bar props type also carried profileName but the status bar never
read it.
* refactor(cli): hoist Kilo model-specific prompt checks to the front
Extract the Kilo metadata-driven prompt selection into a dedicated
kiloPrompt() helper and invoke it with an early return at the top of
provider(). This ensures Kilo-specific prompt routing takes priority
over upstream heuristics and leaves the upstream if-chain untouched,
reducing future merge conflicts when opencode adjusts its own
model-specific prompt branching.
No behavior change.
* fix(cli): preserve Ling prompt fallback precedence
* fix(cli): keep prompt annotations scoped
---------
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
Co-authored-by: marius-kilocode <marius@kilocode.ai>
The new shutdown timeout test in telemetry.test.ts shares a file with
tests that statically import `Telemetry` (and thus `client.ts` and
`posthog-node`). Bun's `mock.module()` invalidates the dependency
cache for subsequent dynamic imports so the test passes today, but the
behavior depends on test ordering and mock-cache-invalidation timing
rather than test isolation. Extract the shutdown test into its own file
where `mock.module("posthog-node", ...)` runs before any client.ts
import, so the mock is the source of truth from module load.
When the PostHog endpoint is unreachable (offline, firewall, DNS adblock
resolving us.i.posthog.com to 0.0.0.0), `kilo --help` and other short-
lived commands hang in the finally-block telemetry shutdown for tens of
seconds before the process exits.
Two issues:
1. `Client.shutdown()` called `await client.flush()` before
`await client.shutdown()`. The explicit flush() is unbounded:
posthog-node 4.4.0 retries each request up to 3x with 3s delays plus
10s per attempt before throwing PostHogFetchNetworkError, blocking
process exit before shutdown's outer cap kicks in.
2. `Telemetry.shutdown()` took no timeout, so the CLI bootstrap had no
way to bound the wait at the call site. PostHog's
`shutdown(shutdownTimeoutMs = 30000)` defaults to 30 seconds.
Fix:
- Drop the explicit `flush()` call. PostHog's `shutdown(timeoutMs)`
drains the queue internally and is bounded by `shutdownTimeoutMs`.
- Add an optional `timeoutMs` parameter to both `Client.shutdown` and
`Telemetry.shutdown`, threaded through to PostHog.
- Pass `2000` from the CLI bootstrap so short-lived commands exit
quickly when telemetry is unreachable, while keeping a generous
budget for the working-endpoint case.
Test: `Telemetry.shutdown timeout (#9788)` mocks `posthog-node` so the
fake `flush()` would hang for 60s if called. The test asserts (a)
`flush()` is never invoked and (b) the supplied `timeoutMs` (50ms) is
threaded through to PostHog's `shutdown(timeoutMs)`. Total elapsed time
stays well under 1s.
Closes#9788
Adds a WWW-Authenticate challenge for unauthorized experimental HttpApi UI fallback responses so browsers open the Basic Auth prompt when a server password is configured.
This script was used to batch-triage open GitHub issues without assignees.
Removing as the triage workflow has evolved and this batch approach is no longer needed.
Removes the automated vouch system that filtered issues and PRs from non-vouched users. This simplifies the contribution process by removing the requirement for maintainers to manually vouch contributors before they can participate.
Switch triage agent to gpt-5.4-nano for faster issue assignment. Remove label
management from the triage tool so it only assigns owners based on team
ownership rules. This reduces noise in the issue tracker and ensures issues
get to the right team member immediately without unnecessary labels.
Update team structures to reflect current ownership and add script for
processing unassigned issues.
The middle-out transform and provider routing settings are not exposed
as dedicated UI controls in the new VS Code extension or CLI, but can
be set via the generic options passthrough in kilo.json. Add inline
kilo.json examples and scope the legacy UI instructions to a separate
tab that no longer promises controls the legacy UI never rendered.
Agents can now create temporary files in the global tmp directory without
triggering external_directory permission prompts. This enables agents to
freely use temporary storage for intermediate files during builds and
other operations.
Git's default rename detection in 'diff --cached --name-only' collapses a
file move (A/foo -> B/foo) into a single destination entry. The snapshot
revert iterates this list and deletes files that aren't in the pre-step
tree — so B/foo was removed but A/foo was never restored, losing data.
Pass --no-renames so both the source and destination paths appear in
the patch, matching diffFull()'s behavior. Revert now deletes the new
location and restores the original.
Fixes#9741
Add version tracking for the shared package alongside the opencode package to improve cache invalidation. Also update the app name from "opencode" to "kilo" in the shared global configuration.
This change ensures that the local binary build process tracks both the opencode and shared package versions, allowing for more accurate cache invalidation when either package changes. The app name update reflects the correct project branding.
Replace the simple model dropdown with a searchable list popup that groups
models into Favorites, Recommended, and provider sections. Favorites are
toggled and persisted through the CLI's model.json via app-level RPC,
matching the CLI TUI and VS Code behavior. Smart filtering matches partial
queries like 'gpt 54' to 'Chat GPT 5.4' using word-boundary acronym matching.
- Move diagram caption outside the overflow:hidden container so it's
no longer clipped by the fixed-height wrapper
- Recommend fine-grained PATs scoped to the connected repository
instead of classic repo-scope tokens (quick-start.md + settings.md)
- Add callout noting agents act on the user's behalf, so limiting
token scope is a best practice
Replace Claude Opus/Sonnet/Auto Free recommendations with Kilo Auto
Frontier (recommended) and Kilo Auto Balanced (minimum). Remove the
per-role model recommendation table since Auto handles routing.
Replace the abbreviated 6-tool table with the complete list of all 21
gt_* tools grouped by category: Work Creation, Convoy Management,
Bead Management, Agent Management, and Town & UI.
Aligns tier names with the user-facing display names ('Auto Free', 'Auto Frontier', etc.). Adds a visible note near every Auto Free mention that prompts may be logged by upstream providers (including NVIDIA's free endpoints) and drops the obsolete ByteDance Dola Seed free model.
The bash tool description now explicitly states that the temp directory has already been created and exists, preventing agents from unnecessarily trying to create it before use.
- Removed @effect/language-service from both packages/core and packages/opencode tsconfig files and dependencies
- Wrapped mergeDeep calls in config loading and LLM streaming to avoid expensive remeda conditional merge type instantiations in hot paths
- Narrowed Drizzle migrate() overload signature to avoid expensive variance checks during database initialization
These changes reduce TypeScript type-checking overhead and improve startup and runtime performance for config loading, LLM streaming, and database migrations.
Edge objects in React Flow don't have sourcePosition/targetPosition —
those properties only exist on Node. Remove them from all edge
definitions in bead-lifecycle, adversarial-loop, and convoy-execution
diagrams. The smoothstep edge type handles routing based on the node
positions instead.
Main flow edges (open→in_progress→in_review→closed) now exit and enter
from the top of each node, arcing above. Failed/rejected transitions
exit from bottom of source to top of target, dropping below.
* fix(kilo-docs): rewrite zenmux doc and add to nav sidebar
Rewrite zenmux.md to match the standard provider doc format
(openrouter, minimax, etc.) and add ZenMux entry to ai-providers nav.
Changes:
- Add sidebar_label frontmatter, Website link, consistent section names
- Remove unrelated API code examples and product feature descriptions
- Add Supported Transforms and Tips and Notes sections
- Fix typo (Visi -> Visit) and codicon syntax
- Add ZenMux to ai-providers nav config
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update packages/kilo-docs/pages/ai-providers/zenmux.md
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* chore: update nix node_modules hashes
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: kilo-maintainer[bot] <kilo-maintainer[bot]@users.noreply.github.com>
- Add preventScrolling={false} and panOnScroll={false} to ReactFlow
so mouse wheel events pass through to the page instead of being
captured by the diagram
- Set explicit sourcePosition/targetPosition on all nodes so edges
connect from right→left for the main horizontal flow
- Use bottom→top routing for failure/rejection transitions so lines
don't overlap nodes
- Reposition 'failed' node and adjust spacing for cleaner layout
Integrate @xyflow/react for interactive architecture diagrams:
- FlowDiagram component with lazy loading (dynamic import)
- Markdoc tag: {% flowDiagram name="..." height="..." /%}
- Three initial diagrams: bead-lifecycle, adversarial-loop, convoy-execution
- Diagrams registry pattern for easy addition of new diagrams
- Replace TODO placeholders in concepts and code-review pages
The diagrams visualize the bead lifecycle state machine, the
micro-adversarial write/review/revise loop, and convoy DAG execution.
Flesh out all 7 sub-pages with comprehensive content:
- Quick Start: town creation, PAT setup, first task flow
- Concepts: towns, beads, convoys, rigs, agents, micro-adversarial loops
- The Mayor: capabilities, tools, communication tips
- Sling Work: single tasks, convoys, staged convoys, DAG execution
- Code Review: refinery pipeline, adversarial loops, merge strategies
- Settings: models, GitHub PAT, merge strategy, env vars, custom instructions
- Troubleshooting: common failure modes and fixes
Includes React Flow diagram placeholders (TODO comments) describing
what each interactive diagram should visualize.
Also moves Gastown nav link under Platforms section with sub-links and
updates page title to 'Gas Town by Kilo'.
Add initial page structure for /code-with-ai/gastown/ with overview,
quick-start, concepts, mayor, sling-work, code-review, settings, and
troubleshooting pages. Register the section in the sidebar nav config.
Fixes 257 typecheck errors surfaced after the upstream merge:
- Update imports to new module paths after upstream PR #24554 removed
module barrel files (@/config, @/session, @/util, etc.) and PR #24309
renamed @opencode-ai/shared to @opencode-ai/core.
- Migrate loadMode to use Info.zod.safeParse for consistency with
loadAgents and ConfigCommand (unblocks KilocodeConfig.handleInvalid).
- Drop removed Npm.outdated mock from tests.
- Add missing Config.defaultLayer to bash-permission-metadata test runtime.
- Fix Tips component signature (kilocode drops upstream's 'connected' prop).
- Fix toast.tsx undefined 'duration' reference (should be toastOptions.duration).
- Move filesystem-containment test from deleted shared package to core.
Relocate the `ui.messagePart.openInDiffViewer` string from the
`packages/ui` locale dictionaries to `packages/kilo-i18n`, removing
the duplicate entries in the UI package and consolidating ownership
of the diff viewer label under a single i18n source.
Introduce `WithEditToolOpenDiffAction` story and supporting
`editCompletedPart` fixture with full filediff metadata to exercise
the `canOpenDiff()` code path. Force-reveal the hover-only action
slot via a scoped style override so visual regression snapshots
capture the icon-button layout.
- Add completed edit tool part with before/after file content
- Wire `onOpenDiff` prop through `AllProviders` into `DataProvider`
- Create dedicated `mockDataEdit` dataset for the new story
Introduce an icon button that appears on hover within the edit-tool
trigger, allowing users to open the diff viewer directly from the
tool header without clicking the file path.
- Add "Open in Diff Viewer" IconButton with tooltip inside edit trigger
- Extract openDiff logic into reusable handler with dedicated click handler
- Style the action button with opacity transition on parent hover/focus
- Add i18n string for "Open in Diff Viewer" label
Provides a small helper for upstream merge workflows so agents can be
allowlisted to search for conflict markers without needing general shell
access. Wraps the canonical ripgrep invocation with a POSIX grep fallback.
* docs(kilo-docs): document codebase indexing for CLI and new VS Code extension
The existing Codebase Indexing page was flagged as legacy-only. Rewrite it to
cover the new shared implementation in the CLI and VS Code extension, including
the `/indexing` command, the `indexing` config section, LanceDB, and the full
list of supported embedding providers.
* docs(kilo-docs): address review feedback on codebase indexing
- Add a top-level warning that indexing is experimental in the CLI and
new VS Code extension
- Add a new 'Enabling the feature' section that documents the
`experimental.semantic_indexing` flag and where to toggle it (CLI
`kilo.jsonc`, VS Code Experimental settings, or legacy direct config)
- Split Embedding Providers and Vector Stores into new-platform vs
VSCode (Legacy) tabs so the legacy section only lists providers it
actually supports (OpenAI, Gemini, Ollama; Qdrant only)
- Fix the Vercel AI Gateway link to point at the product docs
(https://vercel.com/docs/ai-gateway) instead of the raw API endpoint
- Clarify that the Mistral indexing provider uses a La Plateforme API
key, not the Codestral key from the autocomplete setup guide
- Call out the experimental flag prerequisite at each configuration
entry point
* docs(kilo-docs): rename combined tab to 'VSCode & CLI'
* chore: revert unrelated package-lock changes
* docs(kilo-docs): order tabs VSCode, CLI, VSCode (Legacy)
* docs(kilo-docs): consolidate platform-specific indexing docs into one tabs block
Initial high-level design proposal for thumbs up/down feedback on
assistant messages. Covers the problem motivation, scope, payload
differences between Kilo Gateway and direct providers, and open
questions. Implementation details intentionally kept out — those
belong in the PR diff.
Commit 3494a56b2 also removed /docs/kiloclaw/version-pinning alongside the
three flat pages this PR already covers; its content was moved to
/docs/kiloclaw/control-ui/version-pinning. Add the missing redirect so the
old URL no longer 404s.
Commit 3494a56b2 removed /docs/kiloclaw/control-ui, /docs/kiloclaw/pricing,
and /docs/kiloclaw/troubleshooting without adding redirects, producing 404s
on high-traffic URLs. Redirect each to its new nested canonical location.
Every page under /docs/ai-providers was falling back to the site-wide default <title> 'Kilo Code Documentation' because the frontmatter only set sidebar_label. Search ranked these pages at positions 5-8, so unique provider-specific titles should improve click-through and rankings.
download-artifact@v4 silently warned on digest mismatches, which hid the
corrupt `kilo-cli` download on run 25101862100 until the next step
failed with "CLI binary not found". v8 defaults `digest-mismatch`
to `error`, so the same failure surfaces on the download step itself
with an actionable message.
Also switches the build-cli upload to upload-artifact@v7's
`archive: false`, so the already-zstd'd tarball travels as-is instead
of being re-wrapped in a store-only zip. With `archive: false` the
`name:` input is ignored and the artifact is named after the file
(`kilo-cli.tar.zst`), so the two consumers (build-vscode, publish)
now reference `name: kilo-cli.tar.zst` and set `skip-decompress: true`.
The `kilo-vscode` upload stays on v4: it uploads a directory of .vsix
files and `archive: false` requires a single file.
Drops the PostHogSpanExporter that converted AI SDK OpenTelemetry spans
into PostHog ai.* / gen_ai.* events, and disables AI SDK
experimental_telemetry in the CLI so those spans are no longer emitted.
Tool/session/indexing telemetry is unchanged.
Reorganizes the Installation service implementation by grouping info, method, latest, and upgrade methods into a single result object. This improves code locality and makes the service interface more maintainable. Also adds a clarifying comment explaining why the package manager's resolver is used for version lookups (to ensure registries, mirrors, auth, proxies, and dist-tags match upgrade behavior).
Surface startup, workspace, and config issues in the panel so sessions explain why they are unavailable. Let retry refresh warnings first and restart the app when problems persist, while logging final error and warning states on the backend.
The cross-spawn-spawner module has been moved from src/effect/ to src/
to simplify the core package structure. The src/types.d.ts file which
contained unused type declarations has also been removed. All imports
throughout the codebase have been updated to reflect the new location.
This change reduces the package's internal complexity by flattening the
module hierarchy and removing dead code, making future maintenance easier.
Moved the cross-spawn-spawner module from packages/opencode to packages/core
to enable code sharing across the monorepo. This consolidates the process
spawning infrastructure into the core package so other packages can use
cross-platform child process spawning without duplicating the implementation.
Updated all import statements across the codebase to reference the new
location (@opencode-ai/core/effect/cross-spawn-spawner). Removed the
local copy from the opencode package along with its tests.
Move the Global module from packages/opencode/src/global to packages/core/src/global
to provide a unified location for managing XDG directories and application paths.
This eliminates duplicate path definitions across packages and ensures consistent
access to data, config, cache, state, log, and bin directories throughout the codebase.
Moves effect logging, observability, runtime utilities, flags, installation
version info, and process utilities from opencode to core package. This
enables better code sharing across packages and establishes core as the
single source of truth for foundational utilities.
All internal imports updated to use @opencode-ai/core paths for consistency.
Inside a git submodule `git worktree list --porcelain` reports the
gitdir (`<repo>/.git/modules/<sub>`) rather than the actual working
tree, so the worktree-family filter for the experimental session
listing endpoint dropped every session whose directory was the real
submodule path. The CLI `kilo session list` was unaffected because
it filters on `project_id` only.
Append `Instance.worktree` to the parsed dirs so the working tree is
always in scope. Normal repos and linked worktrees already include it,
so the [...new Set(...)] dedup keeps those cases unchanged.
Closes#9267
The permission configuration previously used a generic record type that didn't offer editor completions. Updated the schema to explicitly list all tool permission keys (read, edit, glob, grep, list, bash, task, external_directory, lsp, skill, todowrite, question, webfetch, websearch, codesearch, doom_loop) with proper types, enabling autocomplete when editing permission files.
Keep SessionUi construction phased and align the session test tree with the production package layout so the UI and update flow are easier to navigate. Also pin Kotlin editorconfig defaults so IDE formatting matches repo expectations.
Move controller queue types into a dedicated update package and extract the generic layered root so SessionUi can stay focused on composition. Rename the message list panel to match its role and keep the queue condenser with the update flow.
VS Code's `http.proxySupport: "off"` is the documented opt-in to disable
proxy support entirely. The previous patch returned an empty object in
that case, so the spawned child still inherited ambient shell HTTP_PROXY.
Explicitly set HTTP_PROXY/HTTPS_PROXY/NO_PROXY to "" when proxySupport is
off, and short-circuit before reading `http.proxy` / `http.noProxy` so
the disable setting wins. Two regression tests.
VS Code's http.proxy and http.noProxy settings are not reflected in
process.env, so the CLI server spawned by ServerManager inherits no
proxy configuration. Users behind a corporate proxy see silent auth
failures on the Providers tab and all LLM calls bypass the proxy.
Translate the settings via a small buildProxyEnv() helper and spread
them into the spawn env after process.env (so the VS Code setting
wins when both are present). The standard HTTP_PROXY / HTTPS_PROXY /
NO_PROXY env vars are already honored by Bun's fetch and by most HTTP
clients the CLI reaches for.
Fixes#8213.
Add support for persistently adding the install directory to the Windows user PATH via the registry. This works from Git Bash (MINGW64), MSYS2, and Cygwin, converting paths appropriately and using PowerShell to modify the registry. Also adds to the current session's PATH for immediate use.
JSON and md modes emit clean data to stdout with no decoration.
--quiet now only suppresses progress, never the result output.
Add formatMarkdown and tests.
Filter out models without text output capability (e.g. embeddings,
image-only) since generateText is the wrong probe for them and would
produce false negatives.
Reject non-positive --parallel values that would cause the scheduler to
spin forever, and reject empty filter strings that would bypass the
safety guard and fan out to every configured model.
Adds a new CLI command that allows users to test multiple models for
connectivity and latency in parallel. This helps users discover which
provider/model pairs are available and working.
Features:
- Filter models by regex pattern (e.g., 'kilo roll-call "free"')
- Configurable prompt, timeout, and parallelization
- JSON or table output formats
- Verbose mode for real-time progress
ClosesKilo-Org/kilocode#6304
Closes#8261
reasoningSummary and textVerbosity are OpenAI Responses API parameters
unsupported by generic openai-compatible endpoints. Adds
supportsOpenAIResponsesParams() to gate them by model.api.npm.
reasoningEffort remains universal.
<!-- Reference an existing issue with `Fixes #123`, `Closes #123`, or equivalent linked issue wording. -->
Fixes #
## Context
<!-- Brief description of WHAT you’re doing and WHY. -->
@@ -6,11 +12,13 @@
<!--
Some description of HOW you achieved it. Perhaps give a high level description of the program flow. Did you need to refactor something? What tradeoffs did you take? Are there things in here which you’d particularly like people to pay close attention to?
Some description of HOW you achieved it. Perhaps give a high level description of the program flow. Did you need to refactor something? What tradeoffs did you take? Are there things in here which you’d particularly like people to pay close attention to? Keep this focused on context reviewers cannot infer from the diff; skip file-by-file summaries, placeholders, and other filler.
-->
## Screenshots
## Screenshots / Video
<!-- Required for visual changes. Include the relevant before/after or resulting state. -->
| before | after |
|---|---|
@@ -18,18 +26,49 @@ Some description of HOW you achieved it. Perhaps give a high level description o
## How to Test
### Manual/local verification
<!--
A straightforward scenario of how to test your changes will help reviewers that are not familiar with the part of the code that you are changing but want to see it in action. This section can include a description or step-by-step instructions of how to get to the state of v2 that your change affects.
A "How To Test" section can look something like this:
- Sign in with a user with tracks
- Activate `show_awesome_cat_gifs` feature (add `?feature.show_awesome_cat_gifs=1` to your URL)
- You should see a GIF with cats dancing
Describe local CLI, extension, or docs verification. Example:
- Opened the updated settings page and confirmed the new copy appears
-->
-
### Reviewer test steps
<!--
Provide steps reviewers can retrace. Example:
1. Sign in with a user with tracks
2. Activate `show_awesome_cat_gifs` feature by adding `?feature.show_awesome_cat_gifs=1` to your URL
3. Confirm you see a GIF with cats dancing
-->
-
### Blocked checks and substitute verification
<!--
If a relevant command could not be completed, name the command, explain the blocker or failure, and describe the substitute verification performed. Example:
-`bun run test:integration` could not complete because the required API key is unavailable; substitute verification was testing the affected flow manually in the development extension
-->
-
<!--
Every PR marked ready for review must include testing evidence. A bare "Not tested" or "N/A" answer is not sufficient. For each piece of evidence make clear if the test was executed by the agent or by a human
Docs-only, config-only, and similar changes still need concrete evidence. For examples, see [Testing Evidence for Pull Requests](https://kilo.ai/docs/contributing/development-environment#testing-evidence-for-pull-requests). Draft PRs may be incomplete until marked ready for review.
-->
## Checklist
- [ ] Issue linked above, or exception explained
- [ ] Tests/verification described
- [ ] Screenshots/video included for visual changes, or marked N/A
- [ ] Changeset considered for user-facing changes
- [ ] I personally reviewed the diff and can explain the changes, including any AI-assisted work.
## Get in Touch
<!-- We'd love to have a way to chat with you about your changes if necessary. If you're in the [Kilo Code Discord](https://kilo.ai/discord), please share your handle here. -->
const closeComment = `Closing this pull request because it has had no updates for more than ${DAYS_INACTIVE} days. If you plan to continue working on it, feel free to reopen or open a new PR.`
if (dryRun) {
core.info(`[dry-run] Would close PR #${issue_number} from ${pr.author?.login || 'unknown'}: ${pr.title}`)
continue
}
try {
// Add comment
await withRetry(
() => github.rest.issues.createComment({
owner,
repo,
issue_number,
body: closeComment,
}),
`Comment on PR #${issue_number}`
)
// Close PR
await withRetry(
() => github.rest.pulls.update({
owner,
repo,
pull_number: issue_number,
state: "closed",
}),
`Close PR #${issue_number}`
)
closedCount++
core.info(`Closed PR #${issue_number} from ${pr.author?.login || 'unknown'}: ${pr.title}`)
// Delay before processing next PR
await sleep(requestDelayMs)
} catch (error) {
skippedCount++
core.error(`Failed to close PR #${issue_number}: ${error.message}`)
# required to fetch internal or private CodeQL packs
packages:read
# only required for workflows in private repositories
actions:read
contents:read
strategy:
fail-fast:false
matrix:
include:
- language:actions
build-mode:none
- language:javascript-typescript
build-mode:none
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name:Checkout repository
uses:actions/checkout@v6
# Initializes the CodeQL tools for scanning.
- name:Initialize CodeQL
uses:github/codeql-action/init@v4
with:
languages:${{ matrix.language }}
build-mode:${{ matrix.build-mode }}
config-file:./.github/codeql/codeql-config.yml
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
const commentAge = now - new Date(complianceComment.created_at).getTime();
if (commentAge < twoHours) {
core.info(`${kind} #${item.number} still within 2-hour window (${Math.round(commentAge / 60000)}m elapsed)`);
continue;
}
const closeMessage = isPR
? 'This pull request has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 2-hour window.\n\nFeel free to open a new pull request that follows our guidelines.'
: 'This issue has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 2-hour window.\n\nFeel free to open a new issue that follows our issue templates.';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: item.number,
body: closeMessage,
});
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: item.number,
name: 'needs:compliance',
});
} catch (e) {}
if (isPR) {
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: item.number,
state: 'closed',
});
} else {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: item.number,
state: 'closed',
state_reason: 'not_planned',
});
}
core.info(`Closed non-compliant ${kind} #${item.number} after 2-hour window`);
This recap is specifically for COMMUNITY (external) issues only.
STEP 2: Analyze and categorize
For each issue created today, categorize it:
**Severity Assessment:**
- CRITICAL: Crashes, data loss, security issues, blocks major functionality
- HIGH: Significant bugs affecting many users, important features broken
- MEDIUM: Bugs with workarounds, minor features broken
- LOW: Minor issues, cosmetic, nice-to-haves
**Activity Assessment:**
- Note issues with high comment counts or engagement
- Note issues from repeat reporters (check if author has filed before)
STEP 3: Cross-reference with existing issues
For issues that seem like feature requests or recurring bugs:
- Search for similar older issues to identify patterns
- Note if this is a frequently requested feature
- Identify any issues that are duplicates of long-standing requests
STEP 4: Generate the recap
Create a structured recap with these sections:
===DISCORD_START===
**Daily Issues Recap - ${TODAY}**
**Summary Stats**
- Total issues opened today: [count]
- By category: [bugs/features/questions]
**Critical/High Priority Issues**
[List any CRITICAL or HIGH severity issues with brief descriptions and issue numbers]
**Most Active/Discussed**
[Issues with significant engagement or from active community members]
**Trending Topics**
[Patterns noticed - e.g., 'Multiple reports about X', 'Continued interest in Y feature']
**Duplicates & Related**
[Issues that relate to existing open issues]
===DISCORD_END===
STEP 5: Format for Discord
Format the recap as a Discord-compatible message:
- Use Discord markdown (**, __, etc.)
- BE EXTREMELY CONCISE - this is an EOD summary, not a detailed report
- Use hyperlinked issue numbers with suppressed embeds: [#1234](<https://github.com/${{ github.repository }}/issues/1234>)
- Group related issues on single lines where possible
- Add emoji sparingly for critical items only
- HARD LIMIT: Keep under 1800 characters total
- Skip sections that have nothing notable (e.g., if no critical issues, omit that section)
- Prioritize signal over completeness - only surface what matters
OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/recap_raw.txt
# Extract only the Discord message between markers
sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/recap_raw.txt | grep -v '===DISCORD' > /tmp/recap.txt
IMPORTANT: When counting comments/activity, EXCLUDE these bot accounts:
- copilot-pull-request-reviewer
- github-actions
STEP 3: Identify what matters (ONLY from today's PRs)
**Bug Fixes From Today:**
- PRs with 'fix' or 'bug' in title created/updated today
- Small bug fixes (< 100 lines changed) that are easy to review
- Bug fixes from community contributors
**High Activity Today:**
- PRs with significant human comments today (excluding bots listed above)
- PRs with back-and-forth discussion today
**Quick Wins:**
- Small PRs (< 50 lines) that are approved or nearly approved
- PRs that just need a final review
STEP 4: Generate the recap
Create a structured recap:
===DISCORD_START===
**Daily PR Recap - ${TODAY}**
**New PRs Today**
[PRs opened today - group by type: bug fixes, features, etc.]
**Active PRs Today**
[PRs with activity/updates today - significant discussion]
**Quick Wins**
[Small PRs ready to merge]
===DISCORD_END===
STEP 5: Format for Discord
- Use Discord markdown (**, __, etc.)
- BE EXTREMELY CONCISE - surface what we might miss
- Use hyperlinked PR numbers with suppressed embeds: [#1234](<https://github.com/${{ github.repository }}/pull/1234>)
- Include PR author: [#1234](<url>) (@author)
- For bug fixes, add brief description of what it fixes
- Show line count for quick wins: \"(+15/-3 lines)\"
- HARD LIMIT: Keep under 1800 characters total
- Skip empty sections
- Focus on PRs that need human eyes
OUTPUT: Output ONLY the content between ===DISCORD_START=== and ===DISCORD_END=== markers. Include the markers so I can extract it." > /tmp/pr_recap_raw.txt
# Extract only the Discord message between markers
sed -n '/===DISCORD_START===/,/===DISCORD_END===/p' /tmp/pr_recap_raw.txt | grep -v '===DISCORD' > /tmp/pr_recap.txt
const commentAge = now - new Date(complianceComment.created_at).getTime();
if (commentAge < twoHours) {
core.info(`${kind} #${item.number} still within 2-hour window (${Math.round(commentAge / 60000)}m elapsed)`);
continue;
}
const closeMessage = isPR
? 'This pull request has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 2-hour window.\n\nFeel free to open a new pull request that follows our guidelines.'
: 'This issue has been automatically closed because it was not updated to meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md) within the 2-hour window.\n\nFeel free to open a new issue that follows our issue templates.';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: item.number,
body: closeMessage,
});
try {
await github.rest.issues.removeLabel({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: item.number,
name: 'needs:compliance',
});
} catch (e) {}
if (isPR) {
await github.rest.pulls.update({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: item.number,
state: 'closed',
});
} else {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: item.number,
state: 'closed',
state_reason: 'not_planned',
});
}
core.info(`Closed non-compliant ${kind} #${item.number} after 2-hour window`);
opencode run -m opencode/claude-sonnet-4-6 "A new issue has been created:
Issue number: ${{ github.event.issue.number }}
Lookup this issue with gh issue view ${{ github.event.issue.number }}.
You have TWO tasks. Perform both, then post a SINGLE comment (if needed).
---
TASK 1: CONTRIBUTING GUIDELINES COMPLIANCE CHECK
Check whether the issue follows our contributing guidelines and issue templates.
This project has three issue templates that every issue MUST use one of:
1. Bug Report - requires a Description field with real content
2. Feature Request - requires a verification checkbox and description, title should start with [FEATURE]:
3. Question - requires the Question field with real content
Additionally check:
- No AI-generated walls of text (long, AI-generated descriptions are not acceptable)
- The issue has real content, not just template placeholder text left unchanged
- Bug reports should include some context about how to reproduce
- Feature requests should explain the problem or need
- We want to push for having the user provide system description & information
Do NOT be nitpicky about optional fields. Only flag real problems like: no template used, required fields empty or placeholder text only, obviously AI-generated walls of text, or completely empty/nonsensical content.
---
TASK 2: DUPLICATE CHECK
Search through existing issues (excluding #${{ github.event.issue.number }}) to find potential duplicates.
Consider:
1. Similar titles or descriptions
2. Same error messages or symptoms
3. Related functionality or components
4. Similar feature requests
Additionally, if the issue mentions keybinds, keyboard shortcuts, or key bindings, note the pinned keybinds issue #4997.
---
POSTING YOUR COMMENT:
Based on your findings, post a SINGLE comment on issue #${{ github.event.issue.number }}. Build the comment as follows:
If the issue is NOT compliant, start the comment with:
<!-- issue-compliance -->
Then explain what needs to be fixed and that they have 2 hours to edit the issue before it is automatically closed. Also add the label needs:compliance to the issue using: gh issue edit ${{ github.event.issue.number }} --add-label needs:compliance
If duplicates were found, include a section about potential duplicates with links.
If the issue mentions keybinds/keyboard shortcuts, include a note about #4997.
If the issue IS compliant AND no duplicates were found AND no keybind reference, do NOT comment at all.
Use this format for the comment:
[If not compliant:]
<!-- issue-compliance -->
This issue doesn't fully meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md).
**What needs to be fixed:**
- [specific reasons]
Please edit this issue to address the above within **2 hours**, or it will be automatically closed.
[If duplicates found, add:]
---
This issue might be a duplicate of existing issues. Please check:
- #[issue_number]: [brief description of similarity]
[If keybind-related, add:]
For keybind-related issues, please also check our pinned keybinds documentation: #4997
[End with if not compliant:]
If you believe this was flagged incorrectly, please let a maintainer know.
Remember: post at most ONE comment combining all findings. If everything is fine, post nothing."
opencode run -m opencode/claude-sonnet-4-6 "Issue #${{ github.event.issue.number }} was previously flagged as non-compliant and has been edited.
Lookup this issue with gh issue view ${{ github.event.issue.number }}.
Re-check whether the issue now follows our contributing guidelines and issue templates.
This project has three issue templates that every issue MUST use one of:
1. Bug Report - requires a Description field with real content
2. Feature Request - requires a verification checkbox and description, title should start with [FEATURE]:
3. Question - requires the Question field with real content
Additionally check:
- No AI-generated walls of text (long, AI-generated descriptions are not acceptable)
- The issue has real content, not just template placeholder text left unchanged
- Bug reports should include some context about how to reproduce
- Feature requests should explain the problem or need
- We want to push for having the user provide system description & information
Do NOT be nitpicky about optional fields. Only flag real problems like: no template used, required fields empty or placeholder text only, obviously AI-generated walls of text, or completely empty/nonsensical content.
if: false # kilocode_change - disabled:not needed in kilocode repo
runs-on:blacksmith-4vcpu-ubuntu-2404
permissions:
contents:read
issues:write
steps:
- name:Checkout repository
uses:actions/checkout@v4
with:
fetch-depth:1
- uses:./.github/actions/setup-bun
# kilocode_change start
- name:Setup Kilo
uses:./.github/actions/setup-kilo
# kilocode_change end
- name:Check duplicates and compliance
env:
KILO_API_KEY:${{ secrets.KILO_API_KEY }}
KILO_ORG_ID:${{ secrets.KILO_ORG_ID }}
GITHUB_TOKEN:${{ secrets.GITHUB_TOKEN }}
KILO_PERMISSION:|
{
"bash": {
"*": "deny",
"gh issue*": "allow"
},
"webfetch": "deny"
}
run:|
kilo run -m "kilo/anthropic/claude-haiku-4.5" "A new issue has been created:
Issue number: ${{ github.event.issue.number }}
Lookup this issue with gh issue view ${{ github.event.issue.number }}.
You have TWO tasks. Perform both, then post a SINGLE comment (if needed).
---
TASK 1: CONTRIBUTING GUIDELINES COMPLIANCE CHECK
Check whether the issue follows our contributing guidelines and issue templates.
This project has three issue templates that every issue MUST use one of:
1. Bug Report - requires a Description field with real content
2. Feature Request - requires a verification checkbox and description, title should start with [FEATURE]:
3. Question - requires the Question field with real content
Additionally check:
- No AI-generated walls of text (long, AI-generated descriptions are not acceptable)
- The issue has real content, not just template placeholder text left unchanged
- Bug reports should include some context about how to reproduce
- Feature requests should explain the problem or need
- We want to push for having the user provide system description & information
Do NOT be nitpicky about optional fields. Only flag real problems like: no template used, required fields empty or placeholder text only, obviously AI-generated walls of text, or completely empty/nonsensical content.
---
TASK 2: DUPLICATE CHECK
Search through existing issues (excluding #${{ github.event.issue.number }}) to find potential duplicates.
Consider:
1. Similar titles or descriptions
2. Same error messages or symptoms
3. Related functionality or components
4. Similar feature requests
Additionally, if the issue mentions keybinds, keyboard shortcuts, or key bindings, note the pinned keybinds issue #4997.
---
POSTING YOUR COMMENT:
Based on your findings, post a SINGLE comment on issue #${{ github.event.issue.number }}. Build the comment as follows:
If the issue is NOT compliant, start the comment with:
<!-- issue-compliance -->
Then explain what needs to be fixed and that they have 2 hours to edit the issue before it is automatically closed. Also add the label needs:compliance to the issue using: gh issue edit ${{ github.event.issue.number }} --add-label needs:compliance
If duplicates were found, include a section about potential duplicates with links.
If the issue mentions keybinds/keyboard shortcuts, include a note about #4997.
If the issue IS compliant AND no duplicates were found AND no keybind reference, do NOT comment at all.
Use this format for the comment:
[If not compliant:]
<!-- issue-compliance -->
This issue doesn't fully meet our [contributing guidelines](../blob/dev/CONTRIBUTING.md).
**What needs to be fixed:**
- [specific reasons]
Please edit this issue to address the above within **2 hours**, or it will be automatically closed.
[If duplicates found, add:]
---
This issue might be a duplicate of existing issues. Please check:
- #[issue_number]: [brief description of similarity]
[If keybind-related, add:]
For keybind-related issues, please also check our pinned keybinds documentation: #4997
[End with if not compliant:]
If you believe this was flagged incorrectly, please let a maintainer know.
Remember: post at most ONE comment combining all findings. If everything is fine, post nothing."
kilo run -m "kilo/anthropic/claude-haiku-4.5" "Issue #${{ github.event.issue.number }} was previously flagged as non-compliant and has been edited.
Lookup this issue with gh issue view ${{ github.event.issue.number }}.
Re-check whether the issue now follows our contributing guidelines and issue templates.
This project has three issue templates that every issue MUST use one of:
1. Bug Report - requires a Description field with real content
2. Feature Request - requires a verification checkbox and description, title should start with [FEATURE]:
3. Question - requires the Question field with real content
Additionally check:
- No AI-generated walls of text (long, AI-generated descriptions are not acceptable)
- The issue has real content, not just template placeholder text left unchanged
- Bug reports should include some context about how to reproduce
- Feature requests should explain the problem or need
- We want to push for having the user provide system description & information
Do NOT be nitpicky about optional fields. Only flag real problems like: no template used, required fields empty or placeholder text only, obviously AI-generated walls of text, or completely empty/nonsensical content.
const closeComment = `To stay organized pull requests are automatically closed after ${PR_DAYS_INACTIVE} days of inactivity. If the pull request is still relevant please reopen it or create a fresh new one.`
if (dryRun) {
core.info(`[dry-run] Would close PR #${issue_number} from ${pr.author?.login || 'unknown'} (last activity: ${pr.activity.date.toISOString()} via ${pr.activity.source}): ${pr.title}`)
continue
}
try {
// Add comment
await withRetry(
() => github.rest.issues.createComment({
owner,
repo,
issue_number,
body: closeComment,
}),
`Comment on PR #${issue_number}`
)
// Close PR
await withRetry(
() => github.rest.pulls.update({
owner,
repo,
pull_number: issue_number,
state: "closed",
}),
`Close PR #${issue_number}`
)
closedPrCount++
core.info(`Closed PR #${issue_number} from ${pr.author?.login || 'unknown'} (last activity: ${pr.activity.date.toISOString()} via ${pr.activity.source}): ${pr.title}`)
// Delay before processing next PR
await sleep(prDelayMs)
} catch (error) {
skippedPrCount++
core.error(`Failed to close PR #${issue_number}: ${error.message}`)
}
}
let page = 1
let stop = false
const staleIssues = []
while (!stop) {
core.info(`Fetching page ${page} of open issues...`)
const closeComment = `To stay organized issues are automatically closed after ${ISSUE_DAYS_INACTIVE} days of no activity. If the issue is still relevant please reopen it or create a fresh new one.`
if (dryRun) {
core.info(`[dry-run] Would close issue #${issue.number} (last activity: ${issue.activity.toISOString()} via updated): ${issue.title}`)
continue
}
try {
await withRetry(
() => github.rest.issues.createComment({
owner,
repo,
issue_number: issue.number,
body: closeComment,
}),
`Comment on issue #${issue.number}`
)
await withRetry(
() => github.rest.issues.update({
owner,
repo,
issue_number: issue.number,
state: "closed",
state_reason: "not_planned",
}),
`Close issue #${issue.number}`
)
closedIssueCount++
core.info(`Closed issue #${issue.number} (last activity: ${issue.activity.toISOString()} via updated): ${issue.title}`)
await sleep(issueDelayMs)
} catch (error) {
skippedIssueCount++
core.error(`Failed to close issue #${issue.number}: ${error.message}`)
description: Review an upstream merge PR and write reports
---
Review $1.
Branch off so we have all the code for the reviewed PR. Then run the following reviews in parallel, using one subagent per review, and save each result in the named markdown file at the repository root. A human will read those files, so if in doubt add a finding for human verification.
When all subagents are done, commit the report files and create a draft PR with the reviewed PR branch as base.
Do not include exhaustive per-file checklists in the report files. Summarize the scope and methodology, then list only findings, notable non-findings, command outputs, and limitations.
## KILOCODE_CHANGE_MARKERS.md
Review carefully, file by file, whether we accidentally removed any `kilocode_change` marker.
Get the full list of files changed in the reviewed PR. Check each changed file. For each file, compare both our `main` branch and the upstream-merged version in the reviewed PR. Determine whether any marker removal, marker move, or Kilo-specific change makes sense, and comment on that.
Do not include a full "Files Checked" section. Mention the number of changed files checked, but only list files that have findings or need human verification.
## INFRASTRUCTURE_CHANGE.md
Review whether this PR adds, removes, or changes any infrastructure, such as GitHub Actions, CI config, release/deploy scripts, Docker/build infrastructure, package manager/workspace infrastructure, repository automation, issue templates, changelog automation, or generated SDK/build automation.
We want to merge upstream code but keep our own infrastructure, so flag anything infrastructure-related. When in doubt, add a finding and say a human should check manually.
Do not include a full "Files Checked" section. Only list infrastructure-relevant files and findings.
## OPENCODE_MENTIONS.md
Check whether the merge now mentions OpenCode somewhere user-facing instead of Kilo, or links to OpenCode web properties.
Focus on UI strings, docs, help text, package metadata shown to users, URLs, CLI output, config docs, generated SDK/OpenAPI descriptions, and error messages.
## UNNECESSARY_MARKERS.md
Check whether any merged files now use `kilocode_change` markers without any actual difference to upstream.
Use `script/upstream/find-reset-candidates.ts --dry-run` to see whether any files changed in the PR are actually now identical to upstream. If you find candidates, verify them with `script/upstream/reset-to-upstream.ts --dry-run`.
## BROKEN_PIPELINE_CHAINS.md
Review this PR for broken end-to-end chains where our custom functionality requires changes across multiple files or layers, but the merge may have removed or altered an intermediate step. The code may still compile, so these issues can be silent.
Look for cases like:
- A parameter that is set but never read.
- A field that is populated but never passed through.
- An event that is emitted but no longer handled.
- A config option that is defined but never propagated to where it is used.
- A type definition extended on one side but not consumed on the other.
For each `kilocode_change` in this PR, trace the full chain: where the value or behavior is introduced, where it needs to flow through, and where it is ultimately consumed. Verify every link in the chain still exists after the merge.
Pay special attention to:
- Props or parameters passed through multiple component or function layers.
- Values written to state, context, or storage that are read elsewhere.
- Message types, events, or IPC handlers where sender and receiver must match.
- Configuration or feature flags defined in one place and checked in another.
- Type definitions extended on one side but consumed on the other.
When in doubt, add a finding. A human will verify it. Compiling code is not proof the chain is intact.
## TESTS.md
Check whether this PR removed any Kilo-specific tests.
Kilo-specific tests may live in paths containing `kilo` or `kilocode`, or may include Kilo-specific assertions, fixtures, or `kilocode_change` markers.
The JetBrains plugin currently imports `com.intellij.util.SVGLoader` in `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/ui/SvgIconColorizer.kt` and calls `SVGLoader.load(ByteArrayInputStream(patch()), scale.toFloat())` from `SvgIcon.image(Graphics)`.
Inspection reports this as an internal API usage because `SVGLoader` and its `load(InputStream, float)` method are marked `@ApiStatus.Internal`.
I checked the local IntelliJ source reference via `$INTELLIJ_REPO=/Users/kirillk/products/intellij-community`:
- IntelliJ `SVGLoader.load(stream, scale)` delegates to internal `loadSvg(...)` in `com.intellij.ui.svg`.
- The actual renderer uses `com.github.weisj:jsvg:2.1.0` and renders into a `BufferedImage` with antialiasing, bicubic interpolation, and pure stroke control.
- Copying `SVGLoader.kt` directly would keep references to other internal IntelliJ APIs (`IconLoader`, `ScaleContext`, `ImageUtil`, `SvgAttributePatcher`, `createJSvgDocument`, `renderSvgWithSize`, cache classes, etc.) and would be broader than needed.
## Implementation Plan
1. Add Kilo-owned SVG rendering code under the frontend UI package, for example:
2. Keep the copied implementation minimal and purpose-specific:
- Accept `InputStream` and `scale: Float`.
- Parse the SVG with `com.github.weisj.jsvg.parser.SVGLoader().load(stream)` or the equivalent public jsvg API available in version `2.1.0`.
- Determine image dimensions from the root SVG `width` and `height` already parsed by existing `SvgIconColorizer.size(...)`, or by passing dimensions into the loader if the public jsvg API does not expose reliable intrinsic size.
- Render into `BufferedImage(width * scale, height * scale, BufferedImage.TYPE_INT_ARGB)` using `Graphics2D` rendering hints matching IntelliJ’s `jsvg.kt`:
3. If jsvg does not expose intrinsic size cleanly from public API, adjust the API to avoid duplicating SVG parsing:
- Add `width` and `height` parameters to the Kilo loader.
- In `SvgIcon.image(Graphics)`, call the loader with the already-computed `size.first` and `size.second`.
- This is the likely smallest stable solution because current icons already require explicit `width` and `height` for `SvgIconColorizer.size(...)`.
4. Add the jsvg dependency explicitly to the plugin frontend module instead of relying on the IntelliJ-bundled library:
- In `packages/kilo-jetbrains/gradle/libs.versions.toml`, add `jsvg = "2.1.0"` and `jsvg = { module = "com.github.weisj:jsvg", version.ref = "jsvg" }`.
- In `packages/kilo-jetbrains/frontend/build.gradle.kts`, add `implementation(libs.jsvg)`.
- This follows the package instruction to bundle third-party libraries with the plugin rather than relying on IDE-bundled versions.
5. Update `SvgIconColorizer.kt`:
- Remove `import com.intellij.util.SVGLoader`.
- Replace `SVGLoader.load(ByteArrayInputStream(patch()), scale.toFloat())` with the Kilo-owned loader call.
- Keep the existing color patching, cache key, scale calculation, and size parsing intact.
6. Add a focused frontend unit test:
- New test file: `frontend/src/test/kotlin/ai/kilocode/client/ui/SvgIconColorizerTest.kt` or `SvgLoaderTest.kt`.
- Exercise the actual loader/colorizer with a small SVG resource or inline SVG bytes.
- Assert that rendering returns a non-empty image at scale `1f` and `2f`, and that scaled dimensions are correct.
- If testing the colorizer, paint the icon into a `BufferedImage` and verify at least one expected patched pixel color appears.
7. Run verification from `packages/kilo-jetbrains/`:
-`./gradlew typecheck`
- A targeted frontend test if Gradle supports one cleanly, otherwise `./gradlew test`.
- The requested DevKit internal API inspection is IDE-based; note in final response that the code no longer references `com.intellij.util.SVGLoader`, and typecheck/tests were run.
## Notes And Risks
- The user said “copy SaveLoaer”; I interpret this as “copy `SVGLoader`”. The implementation should copy the relevant rendering behavior, not IntelliJ’s full internal `SVGLoader` object, because the full source depends on multiple other internal APIs and cache infrastructure.
- This change is in `packages/kilo-jetbrains/`, a Kilo-owned package, so `kilocode_change` markers are not needed.
- jsvg package names and constructors should be confirmed during implementation against the downloaded dependency/API available to Gradle. If the API differs from IntelliJ source usage, inspect the source jar or compile error and adapt the minimal wrapper accordingly.
Stop runtime SVG recoloring in the JetBrains plugin and rely on IntelliJ's standard light/dark icon asset resolution. Ensure every SVG asset used by the plugin has a light/dark pair.
## Findings
- Runtime colorization exists only in `frontend/src/main/kotlin/ai/kilocode/client/ui/SvgIconColorizer.kt`.
- The only production caller is `frontend/src/main/kotlin/ai/kilocode/client/session/scroll/ScrollButtonIcon.kt`.
-`ScrollButtonIcon` colorizes two icons at runtime:
-`/icons/scroll-bottom.svg`
-`/icons/scroll-question.svg`
- Both already have dark variants:
-`scroll-bottom_dark.svg`
-`scroll-question_dark.svg`
- Other used frontend icons already have light/dark pairs:
-`plus.svg` / `plus_dark.svg` exists, though no current direct source reference was found.
-`kilo@20x20.svg` / `kilo@20x20_dark.svg` exists, though no current direct source reference was found.
-`src/main/resources/META-INF/pluginIcon.svg` is present and has no `pluginIcon_dark.svg`. It is not referenced in source/XML, but JetBrains treats this filename conventionally as plugin metadata/marketplace icon, so it should be paired for completeness.
- The SVG assets use literal colors and no `currentColor`, `<style>`, CSS classes, or CSS variables were found in `frontend/src/main/resources/icons/*.svg`.
## Implementation Plan
1. Replace `ScrollButtonIcon` runtime colorization with standard `IconLoader.getIcon(...)` loading.
- Remove imports for `colorizedSvgIcon`, `SessionUiStyle`, `UiStyle`, `JBUI`, and `Color` from `ScrollButtonIcon.kt`.
- Add `IconLoader` import.
- Load `bottom` with `IconLoader.getIcon("/icons/scroll-bottom.svg", ScrollButtonIcon::class.java)`.
- Load `prompt` with `IconLoader.getIcon("/icons/scroll-question.svg", ScrollButtonIcon::class.java)`.
- Keep `create(question: Boolean = false)` unchanged so callers continue to receive the appropriate icon.
- IntelliJ should automatically resolve `_dark.svg` variants when the look and feel is dark.
2. Delete `frontend/src/main/kotlin/ai/kilocode/client/ui/SvgIconColorizer.kt` after confirming no callers remain.
3. Remove now-unused scroll icon source palette constants from `SessionUiStyle.ScrollIcon`.
- Delete the `ScrollIcon` object if no references remain.
- This also removes stale comments about runtime colorization.
4. Add `src/main/resources/META-INF/pluginIcon_dark.svg` as the dark-mode pair for `pluginIcon.svg`.
- Use the same artwork/colors as `pluginIcon.svg` unless there is a desired brand-specific dark variant; the current icon already has a black background and yellow mark, so an identical dark pair is acceptable and satisfies IntelliJ's expected pair convention.
5. Re-scan the JetBrains package after edits.
- Confirm there are no `colorizedSvgIcon` or `SvgIconColorizer` references.
- Confirm every used SVG path has a sibling `_dark.svg` where IntelliJ expects one.
- Confirm no frontend SVG uses `currentColor`, `<style>`, CSS classes, or CSS variables.
6. Run the smallest relevant verification from `packages/kilo-jetbrains/`:
- The scroll icons will no longer follow arbitrary runtime theme colors; they will use the static light/dark SVG asset colors. This matches the requested behavior.
- If a non-default theme expects palette overrides, static literal SVG colors still follow normal IntelliJ SVG handling better than custom byte-patching, but the exact custom-color behavior may differ from the old colorizer.
When a question-like active view first appears in the JetBrains session UI, do not auto-scroll the transcript if the user is already away from the tail and the scroll-to-bottom button is visible. This applies to permission prompts and question-based views. Existing behavior should remain: if the transcript is already at the bottom, new questions/permissions keep the view at the bottom; explicit question navigation can still jump to the active card.
## Current Findings
-`SessionUi` wires `QuestionView` with:
-`follow = { scroll.following() }`
-`scroll = { scroll.followBottom(it) }`
-`QuestionView.show()` runs on first display and calls:
-`val tail = follow()` before rendering the card
-`scroll(tail)` after rendering
-`SessionScroll.following()` currently returns `component.viewport.view === messages && tail`.
- This can use stale internal follow state instead of the live scrollbar state. The user-visible condition is better represented by `SessionScroll.atBottom()`, which is also what `SessionController.beforeUpdate` uses for normal transcript updates.
- Existing `SessionScrollTest` already covers question and login-required middle-scroll preservation, but it does not cover permission first appearance and likely does not cover a stale-tail/live-not-at-bottom edge.
## Implementation Plan
1. Update question first-show follow sampling to use live bottom state.
- In `SessionUi.buildUi()`, change the `QuestionView``follow` lambda from `scroll.following()` to `scroll.atBottom()`.
- Alternatively, if a single semantic API is preferred, change `SessionScroll.following()` to return `component.viewport.view === messages && atBottom()` and keep the `SessionUi` call site unchanged. Prefer the smaller, clearer call-site change unless tests show other `following()` behavior should change too.
2. Add permission scroll regression tests in `SessionScrollTest`.
- Add `test permission appearing at bottom keeps scroll at bottom`.
- Add `test permission appearing while user is in middle preserves scroll position`.
- Emit `ChatEventDto.PermissionAsked("ses_test", PermissionRequestDto(...))` using the same DTO style as the existing recovered permission test.
- Assert the scrollbar value is preserved and `jumpButton().isVisible` stays true when initially away from bottom.
3. Strengthen question regression coverage if needed.
- Keep the existing `test question appearing while user is in middle preserves scroll position`.
- If the bug reproduces only when the jump button is visible but `tail` can be stale, add a targeted regression that creates the visible jump state before `QuestionAsked` and asserts first display does not jump.
- Avoid adding production-only test hooks; use existing `setValue`, `setValuePassive`, `drainScroll`, and event helpers.
- Do not change `QuestionView.goForward()`, `goBack()`, or `goReview()`, which intentionally call `scroll(true)` and are covered by existing tests that expect navigation to jump to the active question card.
- Do not change prompt growth or normal streaming follow behavior unless a failing test shows the same stale-state issue applies there.
5. Verification.
- Run the targeted JetBrains frontend session scroll tests from `packages/kilo-jetbrains/` using Gradle test filtering for `SessionScrollTest` if supported.
- Run `./gradlew typecheck` from `packages/kilo-jetbrains/` if the targeted tests pass or if Gradle filtering is unavailable.
- If Java 21 is unavailable, first check/report that blocker as instructed by the repo docs.
Fix JetBrains session scrolling so that when any inline prompt card appears while the scroll/jump button is already visible, the transcript scroll position is preserved and only the scroll button state changes. This applies to all current `BaseQuestionView`-backed session cards: questions, permissions, and login-required prompts. Preserve existing behavior that question navigation, review/back/next, and bottom-following content changes auto-scroll when they are supposed to.
## Findings
- The relevant files are `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/SessionUi.kt`, `.../scroll/SessionScroll.kt`, `.../views/question/QuestionView.kt`, `.../views/permission/PermissionView.kt`, `.../views/LoginRequiredView.kt`, `.../views/base/BaseQuestionView.kt`, and `frontend/src/test/kotlin/ai/kilocode/client/session/SessionScrollTest.kt`.
-`QuestionView`, `PermissionView`, and `LoginRequiredView` do not inherit from `BaseQuestionView`; they compose it as the shared card shell. Scroll behavior should stay outside `BaseQuestionView` because it is a pure visual component with no session scroll context.
- The current uncommitted `SessionUi.kt` attempt changes `QuestionView` from `follow = { scroll.following() }` to `follow = { scroll.atBottom() }`.
- That fixes initial question appearance when the user is visibly away from bottom, but it is too broad because `QuestionView.follow()` is also used after custom editor growth, selection refresh, reply/reject, and other internal updates.
-`QuestionView` already intentionally calls `scroll(true)` in `goBack`, `goForward`, and `goReview`; those forced calls are the behavior that preserves auto-scroll when switching question pages.
-`PermissionView.show()` and `LoginRequiredView.show()` do not call scroll directly. They rely on `SessionController.beforeUpdate` / `afterUpdate`, which samples `scroll.atBottom()` before the state change and calls `scroll.followBottom(follow)` afterward. With the stale-tail fix, this path can preserve scroll for all non-question inline prompt cards.
- The uncommitted `SessionScroll.followBottom(false)` change that clears stale `tail` when the transcript is visible and not actually at bottom is directionally correct. It prevents later `following()` calls from resurrecting auto-follow after a non-follow decision.
- The current scroll button pending state is named `question` / `setQuestionPending` and is only enabled for non-plan `AwaitingQuestion`. To cover all `BaseQuestionView`-backed prompts, this should become a generic pending-input/attention state and include `AwaitingPermission` and `LoginRequired`.
- Existing behavior intentionally keeps plan follow-up questions using the normal scroll icon (`test plan followup question keeps scroll icon`), so preserve that exception unless product intent changes separately.
- The uncommitted `build.gradle.kts` and `script/build-sign-check.sh` changes are unrelated to this bug and should not be touched as part of this fix.
## Implementation Plan
1. In `QuestionView.kt`, split the scroll-follow decision into two callbacks.
- Keep the existing `follow` callback for question-internal updates.
- Add a second callback for initial question appearance, with a default that delegates to `follow` so existing tests/call sites remain compatible.
- In `show(q)`, sample the new initial callback before making the question visible or rebuilding the card, then call `scroll(tail)` after `syncPage()` as today.
- Leave `scroll(true)` in `goBack`, `goForward`, and `goReview` unchanged.
- Leave existing `scroll(follow())` calls in custom editor changes, option selection, reply, and reject paths unchanged.
2. In `SessionUi.kt`, wire the callbacks with distinct meanings.
- Use `follow = { scroll.following() }` for question-internal updates.
- Use the new initial callback as `{ scroll.atBottom() }` for initial question appearance.
- Keep `scroll = { scroll.followBottom(it) }`.
3. Generalize the scroll button pending state for all inline prompt cards.
- Rename `SessionScroll.setQuestionPending` and the backing `question` boolean to a generic name such as `setInputPending` / `pending` or `setAttentionPending` / `pending`.
- Rename `questionPending(state)` in `SessionUi.kt` to match the broader meaning.
- Return `true` for non-plan `SessionState.AwaitingQuestion`, `SessionState.AwaitingPermission`, and `SessionState.LoginRequired`.
- Keep returning `false` for plan follow-up questions so the existing plan-specific icon behavior is preserved.
- Reuse the existing question-style icon and tooltip for now, unless a separate product decision asks for a different permission/login-specific icon or string.
4. In `SessionScroll.kt`, keep the stale-tail reconciliation in `followBottom(false)`.
- When `follow` is false, increment `seq`, and if the active view is the transcript and `!atBottom()`, set `tail = false` before `updateJump()`.
- Do not change `following()` to use `atBottom()`, because `tail` is needed to preserve bottom-follow behavior across deferred layout/height growth.
5. Do not add scroll callbacks to `PermissionView`, `LoginRequiredView`, or `BaseQuestionView` unless tests prove the controller-level path is insufficient.
-`PermissionView` and `LoginRequiredView` should remain retained visual views that show/hide themselves and refresh their parent.
-`BaseQuestionView` should stay a scroll-unaware card shell.
- The shared behavior for those cards should come from the controller-level state-change follow decision plus the generalized pending-button state.
6. In `SessionScrollTest.kt`, update tests around question-style prompt appearance and preserved behavior.
- Keep or add an assertion that the jump button is visible before emitting a question in the middle-scroll test.
- Keep a regression for stale `tail` plus visible jump button if no public-only scenario can reproduce the failed state; keep the reflective helper local to this test file and avoid adding production test hooks.
- Keep existing behavior tests for question navigation from the middle, forced navigation resuming follow, custom question answer growth at bottom, custom question answer growth in the middle, and option selection not resuming follow.
- Add or keep permission bottom/middle tests to prove `AwaitingPermission` preserves scroll when away from bottom and follows when at bottom.
- Add or keep login-required bottom/middle tests to prove `LoginRequired` preserves scroll when away from bottom and follows when at bottom.
- Add explicit button-state assertions for permission and login-required while away from bottom: the button remains visible, switches to the pending-input icon/tooltip, and clicking it still scrolls to bottom.
- Keep the plan follow-up test proving plan prompts do not switch to the pending-input icon.
7. Add a patch changeset for the JetBrains plugin unless an existing branch changeset is intentionally covering this exact fix.
- Suggested release note: `Preserve JetBrains chat scroll position when inline prompts appear while the scroll button is visible.`
## Verification
- From `packages/kilo-jetbrains/`, run `./gradlew test --tests "ai.kilocode.client.session.SessionScrollTest"`.
- From `packages/kilo-jetbrains/`, run `./gradlew typecheck`.
- Do not run root `bun test`.
## Expected Outcome
- If the transcript is away from bottom and the jump button is visible, a newly appearing question, permission prompt, or login-required prompt changes the button state without moving `bar.value`.
- If the transcript is at bottom, a newly appearing question, permission prompt, or login-required prompt follows to the new bottom.
- Clicking the visible pending-input scroll button still jumps to the bottom for every inline prompt card.
- Question carousel next/back/review still jumps to the bottom even if the transcript was previously in the middle.
- Custom question editor growth still follows when the transcript was following and preserves position when it was not.
-`setRequestFocus(false)` / `setFocusable(false)` if we want the popup not to steal focus
-`setCancelOnClickOutside(true)` for outside-click dismissal
-`setCancelKeyEnabled(true)` for Escape dismissal
-`setCancelOnWindowDeactivation(true)` and `setCancelOnOtherWindowOpen(true)` are available and appropriate for cleanup
- IntelliJ platform icons found in `AllIcons`:
- Feedback button: `AllIcons.Ide.Feedback`
- GitHub action: `AllIcons.Vcs.Vendors.Github`
- Support/help action: `AllIcons.Actions.Help` or `AllIcons.General.ContextHelp`
- Discord: no platform icon found. Add a Discord icon by borrowing the existing VS Code/kilo-ui Discord SVG artwork and adapting it into the JetBrains plugin resources with IntelliJ-compatible SVG colors and dark variant if needed.
## Implementation Steps
1. Add localized JetBrains bundle keys.
- Add base English strings to `frontend/src/main/resources/messages/KiloBundle.properties`:
-`feedback.button=Feedback & Support`
-`feedback.dialog.message=We'd love to hear your feedback or help with any issues you're experiencing.`
-`feedback.dialog.github=Report an issue on GitHub`
- Reuse existing cancel text if present; otherwise add `common.cancel=Cancel` only if needed.
- Add matching keys to localized `KiloBundle_*.properties` files. If accurate translations are not already available from the VS Code i18n files, copy the VS Code translations for matching locales where practical and leave English fallback only if the JetBrains bundle mechanism supports it cleanly.
2. Extend `EmptySessionPanel` UI.
- Add a new retained `FeedbackButton`, styled to match VS Code conceptually:
- feedback icon + `Feedback & Support` text
- dashed link-colored border
- transparent background
- hand cursor
- hover state fills with link color and flips foreground/background for contrast
- Use IntelliJ theme APIs instead of raw colors:
- link color: `JBUI.CurrentTheme.Link.Foreground.ENABLED`
- hover link color: `JBUI.CurrentTheme.Link.Foreground.HOVERED` if useful
- editor/panel background from existing session style or `UiStyle.Colors.editorBackground()` / component background
- spacing via `UiStyle.Gap` / `JBUI.Borders`
- rounded arc via `UiStyle.Arc.component()` or `JBUI.getInt("Button.arc", 6)` at paint time
- Add the feedback button below the existing `Show History` button in the empty-state south area, keeping the current centered layout.
- Keep Swing mutations on EDT and preserve retained-component behavior.
3. Implement the feedback popup in frontend Swing code.
- Add a small popup builder method/class inside `EmptySessionPanel.kt` or a new nearby UI file if the file would become too large.
- Content should mirror VS Code:
- Kilo logo at top using existing `/icons/kilo-content.svg`
- message text
- three action buttons/rows for GitHub, Discord, and Customer Support
- every action should have an icon: `AllIcons.Vcs.Vendors.Github` for GitHub, the borrowed Discord SVG for Discord, and `AllIcons.Actions.Help` or `AllIcons.General.ContextHelp` for Customer Support
- optional Cancel button if it fits the JetBrains UX; Escape/outside click already dismisses
- Add the Discord icon asset under `frontend/src/main/resources/icons/` using the plugin's existing icon naming pattern, for example `discord.svg` and `discord_dark.svg` if the borrowed asset needs separate theme variants.
- Load the Discord icon with `IconLoader.getIcon("/icons/discord.svg", EmptySessionPanel::class.java)` or a small Kilo-owned icon object if multiple call sites need it.
- Use `BrowserUtil.browse(url)` to open links.
- Close the popup after opening a URL.
- Use `JBPopupFactory.createComponentPopupBuilder(content, null)` and configure:
-`.setModalContext(false)`
-`.setRequestFocus(false)`
-`.setFocusable(false)` unless keyboard tabbing inside popup is desired; if buttons need keyboard focus, use `.setFocusable(true)` with `.setRequestFocus(false)`
-`.setCancelOnClickOutside(true)`
-`.setCancelKeyEnabled(true)`
-`.setCancelOnWindowDeactivation(true)`
-`.setCancelOnOtherWindowOpen(true)`
-`.setResizable(false)`
-`.setMovable(false)`
- Show with `popup.showUnderneathOf(feedbackButton)`.
4. Add test coverage in `EmptySessionPanelTest.kt`.
- Assert feedback button text uses `KiloBundle.message("feedback.button")`.
- Assert feedback button has hand cursor and visible border semantics.
- Add an injectable browse callback or popup action callback only if needed for testing without launching browsers; keep it minimal and avoid production-only test hooks if component traversal can exercise enough behavior.
- Add a test that clicking the feedback button creates/shows popup content, if feasible in `BasePlatformTestCase`; otherwise test the retained popup content builder/action rows directly through package-internal methods.
- Assert the three action labels exist and URL callbacks map to the same URLs as VS Code.
- Assert the Discord action has an icon, so the plan cannot regress to a text-only Discord row.
5. Add release note.
- This is user-facing for the JetBrains plugin, so add a patch changeset under `.changeset/` unless the repo has a JetBrains-specific release-note mechanism that supersedes changesets.
- Suggested text: `Add Feedback & Support to the JetBrains empty session screen.`
6. Verify.
- Run the focused frontend/JetBrains tests first, preferably from `packages/kilo-jetbrains/`:
- Run JetBrains typecheck from `packages/kilo-jetbrains/`:
-`bun run typecheck` or `./gradlew typecheck`
- If touching only frontend UI and tests pass, no backend/SDK generation is needed.
## Notes
- Do not add Kotlin UI DSL, Compose, or JCEF.
- Do not modify shared opencode files; this work is entirely under `packages/kilo-jetbrains/` plus a changeset.
- Prefer platform icons where available, but explicitly borrow/add the Discord icon because `AllIcons` does not provide one and the popup should match the VS Code button set visually.
Keep JetBrains markdown layout compact while making markdown colors and backgrounds come from the active editor color scheme, and ensure existing theme/editor-setting listeners refresh all existing `MdView` instances after changes.
## Findings
-`SessionUi` already subscribes to `EditorColorsManager.TOPIC` and `LafManagerListener.TOPIC`, then calls `applyStyle(SessionEditorStyle.current())` on the session tree.
- Most markdown consumers already propagate that style through `MdView.applyStyle(style)` via `TextView`, `ReasoningView`, message lists, and session panels.
-`PlanExitView.applyStyle()` sets only font/code font/foreground and does not call `md.applyStyle(style)`, so internal markdown role colors can stay tied to the initial style.
-`MdViewHybrid.applyStyle()` restyles retained HTML panes and code block containers, but retained `CodeField` editors need explicit reapplication of `SessionEditorStyle.applyToEditor()` after creation so syntax highlighting and editor colors follow scheme changes.
-`MdCommon.defaults()` currently mixes editor colors, UI theme colors, and one literal inline-code color fallback. The literal fallback should be removed, and markdown roles should derive from `EditorColorsScheme`/syntax attributes wherever possible.
-`TextView` currently overrides markdown background with `SessionUiStyle.Transcript.bgColor()` (`UiStyle.Colors.bg()`), while prompt markdown already uses `style.editorBackground`. If markdown surfaces should consistently use editor background, normal text views need to use `style.editorBackground` too.
## Implementation Plan
1. Keep compact CSS unchanged.
- Do not reintroduce line-height, margin, padding, heading sizing, or other geometry rules.
- Keep the current role color/background selectors only.
2. Derive markdown role defaults from editor settings.
- Update `MdCommon.defaults(style)` to use `style.editorForeground` and `style.editorBackground` for primary text/background.
- Add small local helper functions for editor attributes, for example foreground/background from `style.editorScheme.getAttributes(key)` and color keys from `style.editorScheme.getColor(key)`.
- Use public IntelliJ editor keys for role colors:
- Links: `CodeInsightColors.HYPERLINK_ATTRIBUTES.foregroundColor`, fallback to platform link color if absent.
- Inline code foreground/background: `DefaultLanguageHighlighterColors.DOC_CODE_INLINE`, fallback to `STRING`, then editor foreground/background.
- Code block foreground/background: `DefaultLanguageHighlighterColors.DOC_CODE_BLOCK`, fallback to editor foreground/background.
- Quote/emphasis/list weak text: comment/doc-comment attributes, fallback to editor foreground or `UIUtil.getContextHelpForeground()` only when the scheme has no useful value.
- Borders/HR/table/code border: editor preview/border color keys such as `EditorColors.PREVIEW_BORDER_COLOR`, fallback to `UiStyle.Colors.contentBorder()`.
- Remove `JBColor(0x...)` or other literal runtime color fallbacks from `MdCommon`.
- Keep public `MdView` API unchanged; role colors stay internal unless a concrete external override need appears.
3. Ensure style propagation reaches every markdown instance.
- Update `PlanExitView.applyStyle(style)` to call `md.applyStyle(style)` before applying its explicit font/code-font/foreground overrides.
- Audit existing markdown callers after the change; keep using the existing `SessionEditorStyleTarget` propagation path rather than adding per-`MdView` theme listeners.
- Keep explicit foreground overrides in `TextView`, `ReasoningView`, and `PlanExitView` where they intentionally set body text role, but let internal markdown role colors refresh from the new style snapshot.
- In `MdViewHybrid.CodeView.style(opts)`, for retained `CodeField` blocks, reapply `style.applyToEditor(editor)` to the underlying editor if it exists.
- Reapply code editor background/scroll pane/viewport backgrounds from `opts.preBg` in the same path.
- Preserve retained component/editor reuse: do not rebuild code block panes just to update style.
5. Align markdown backgrounds with editor settings.
- Keep `MdCommon` default background as `style.editorBackground`.
- Change normal `TextView` markdown background to `style.editorBackground` if the intent is that all markdown surfaces use editor background, matching `PromptView` and session root behavior.
- Preserve `transparent` handling: when `md.opaque = false`, background should still be the editor-derived value for child/code surfaces, but the Swing component should remain non-opaque.
6. Update tests.
- Extend `MdViewTest` to verify markdown role CSS changes when applying a `SessionEditorStyle` backed by a customized editor scheme, especially inline code, code block, link, and border colors.
- Extend `MdViewHybridTest` to assert `applyStyle()` updates retained HTML panes and retained code editors without replacing them, including editor scheme/background changes.
- Add or extend `PlanExitViewTest` so `applyStyle()` refreshes the nested markdown style, not just foreground/font overrides.
- Keep existing compactness expectations: tests should not assert new spacing, padding, margin, line-height, or size rules.
## Verification
- From `packages/kilo-jetbrains/`, run `./gradlew frontend:test --tests '*MdView*'`.
- From `packages/kilo-jetbrains/`, run `./gradlew frontend:test --tests '*PlanExitViewTest*'` if the focused test is not covered by the MdView filter.
- From `packages/kilo-jetbrains/`, run `bun run typecheck`.
## Constraints
- Do not introduce JCEF, Compose, or Kotlin UI DSL.
- Do not add new theme/editor listeners in `MdView`; use the existing `SessionUi` listener and `SessionEditorStyleTarget` propagation path.
- Avoid hardcoded runtime colors in markdown styling; prefer editor scheme attributes/color keys, then platform/theme APIs as non-literal fallbacks.
- Preserve retained Swing behavior and `MdViewHybrid.sync()` component reuse.
- Keep the public `MdView` override API stable unless implementation proves a new external override is required.
Improve JetBrains markdown output so assistant/user transcript markdown visually matches the VS Code webview markdown style while keeping the existing Swing/JBHtmlPane + editor-backed code block architecture.
## Findings
- VS Code markdown styling is split across `packages/ui/src/components/markdown.css`, `packages/kilo-ui/src/components/markdown.css`, `packages/kilo-ui/src/styles/vscode-bridge.css`, and message-part overrides.
- Base VS Code markdown uses 14px sans text, 160% line height, tight first/last margins, same-size medium headings, 12px paragraph spacing, link-colored anchors, compact lists, weak list markers, weak blockquotes with a 2px left border, invisible HR spacing, bordered/padded code blocks, green inline code, and lightly bordered tables.
- The VS Code theme bridge maps markdown roles to editor/theme tokens: heading/link/list/image use `textLinkForeground`, text/strong/code-block use editor foreground, inline code uses charts/syntax green, quote/emphasis use description foreground, HR uses panel border.
- JetBrains markdown is rendered by `MdViewHybrid` and `MdViewHtmlPane`, with shared CSS from `MdCommon.rules()` and defaults from `MdCommon.defaults()`.
- JetBrains currently styles only broad tag font/color, links, code/pre colors, blockquote border/text color, and table border. It lacks VS Code-equivalent spacing, heading/strong/emphasis/list marker/table cell rules, inline-code foreground, blockquote geometry, HR spacing, and code block surface polish.
- JetBrains fenced code blocks are already stronger than VS Code in one respect: they use `EditorTextField` with real IDE syntax highlighting and streaming retention. Preserve this instead of switching to web/JCEF rendering.
## Implementation Plan
1. Expand JetBrains markdown style tokens.
- Add internal fields to `MdStyle` for heading, strong, emphasis, inline code foreground, list marker, HR, table/header, and code block border colors.
- Keep the public `MdView` override API stable unless a new external override is clearly needed.
- Compute defaults in `MdCommon.defaults(style)` from IntelliJ/editor theme sources and centralized Kilo semantic colors where no platform key matches.
- Use `JBColor.namedColor("Kilo.Markdown.*", fallback)` for Kilo-specific markdown palette fallbacks, so themes can override them and runtime code avoids scattered hardcoded colors.
2. Mirror VS Code markdown CSS in `MdCommon.rules()`.
- Add root/body wrapping rules: max width behavior, break-word wrapping, base line-height, and first/last-child margin trimming where supported by `JBHtmlPane` CSS.
- Add heading rules: same base size, medium/bold weight, role-specific color, line height, and bottom spacing.
- Add paragraph, list, list item, nested list, and marker rules. If Swing HTML does not support `::marker`, fall back to `li { color: ... }` plus child text color reset only if supported; otherwise keep list text normal and document the limitation in tests.
- Add strong/emphasis colors matching VS Code token roles.
- Add anchor styling matching VS Code: themed link color, no forced background, and underline behavior where `JBHtmlPane` supports it.
- Add blockquote geometry: 2px left border, 24px vertical margin, 8px left padding, weak text, and normal style.
- Keep HRs visually hidden but spaced consistently with VS Code if the renderer includes them. `MdViewHybrid` currently filters thematic breaks, so this mainly benefits `MdViewHtmlPane` and future reuse.
- Add inline-code foreground and medium font weight. Avoid inline code backgrounds unless the current `JBHtmlPane` configuration already draws them acceptably.
3. Polish JetBrains code block containers without losing IDE highlighting.
- Keep `EditorTextField` for fenced/indented blocks and `JBTextArea` fallback.
- Style `JBScrollPane` code blocks to match VS Code’s `markdown-code` wrapper feel: subtle background, subtle border, rounded-ish platform arc if feasible, 12px-ish padding, and thin horizontal scrollbar behavior.
- Use `SessionUiStyle.View.Code` for geometry constants. Add only minimal new constants there if current values cannot represent the VS Code spacing.
- Separate code block border color from table border internally so table styling can change without affecting code boxes.
- Continue applying `SessionEditorStyle.applyToEditor(ed)` so code blocks follow IDE syntax highlighting and editor font changes.
4. Add file/path affordance parity where safe.
- For markdown links whose `href` looks like a relative file path, keep existing link dispatch so the current caller can open files/URLs appropriately.
- Consider decorating inline code that looks like a path with a `file-link` class only when an `openFile` callback is available through the existing usage path. If the current `MdView` abstraction only has `openUrl`, do not widen it unless the call sites can pass file opening cleanly.
- At minimum, make inline code/path-looking content visually closer to VS Code by using the inline-code foreground and dotted underline for explicit file links where generated HTML contains link/code classes.
- Ensure style updates call `reloadCssStylesheets()` and reassign text only for retained `JBHtmlPane` blocks, not by rebuilding all blocks.
- Keep streaming fenced-code fast path and editor disposal behavior intact.
6. Add focused tests.
- Extend `MdViewTest` and/or `MdViewHybridTest` to assert `overrideSheet()` contains the new VS Code-equivalent rules for headings, strong/emphasis, links, inline code foreground, list/table/blockquote spacing, HR, and code block/table border separation.
- Add component tests for code block pane styling: background, viewport background, border color, padding, scrollbar policy, and retained editor instance after `applyStyle()`.
- Keep existing stress/leak tests green. Add a small stress assertion only if the implementation changes style application semantics.
- Add a changeset: `@kilocode/kilo-jetbrains` patch with user-facing wording such as `Improve markdown readability in JetBrains chat transcripts.`
## Verification
- Run targeted JetBrains markdown tests first from `packages/kilo-jetbrains/`: `./gradlew frontend:test --tests '*MdView*'` if the Gradle module supports it; otherwise run the closest supported targeted Gradle test command.
- Run `bun run typecheck` from `packages/kilo-jetbrains/`.
- If targeted Gradle filtering is unreliable, run `./gradlew test` from `packages/kilo-jetbrains/`.
## Constraints
- Do not introduce JCEF, Compose, or Kotlin UI DSL.
- Keep changes inside `packages/kilo-jetbrains/` and `.changeset/` unless a shared Kilo UI source of truth is explicitly required.
- No `kilocode_change` markers are needed for JetBrains or Kilo UI paths.
- Prefer IntelliJ theme APIs and centralized semantic tokens over scattered literal colors.
- Use Kilo/VS Code-aligned session icons in session views.
- Fix the reasoning header icon.
- Normalize session part collapse/expand chevrons so collapsed/expanded states do not jump between differently sized glyphs.
- Move the session-details toggle away from compaction and place it before the session title.
## Findings
- Session view icons are centralized in `packages/kilo-jetbrains/frontend/src/main/kotlin/ai/kilocode/client/session/views/SessionViewIcons.kt` and loaded from `frontend/src/main/resources/icons/views/*.svg`.
- The JetBrains `views` SVGs already mirror the shared VS Code/UI icon paths from `packages/ui/src/components/icon.tsx` for the audited names, including `brain`, `chevron-down`, `chevron-right`, `checklist`, `console`, `warning`, etc.
- The reasoning view currently renders `SessionViewIcons.eye` in `ReasoningView.kt`; VS Code/shared UI uses the `brain` icon for reasoning/thinking surfaces, and `SessionViewIcons.brain` already exists.
- Standard collapsible session parts use `SessionViewIcons.chevronDown` when expanded and `SessionViewIcons.chevronRight` when collapsed in `AbstractSessionPartView.kt`; `QuestionResultView.kt` repeats this pattern manually. The down/right SVG paths have different visual extents.
- The session header currently places the details toggle next to the compact button in the right-side controls in `SessionHeaderPanel.kt`, making the two actions easy to confuse.
## Implementation Steps
1.**Keep icon sources aligned with VS Code/shared UI**
- Treat `packages/ui/src/components/icon.tsx` as the source for Kilo web/session glyph shapes.
- Re-check `SessionViewIcons.kt` entries against available JetBrains assets; only update or add SVGs if a session view uses a Kilo icon missing from `frontend/src/main/resources/icons/views/`.
- Preserve JetBrains SVG theming rules: no `currentColor`; use literal palette colors and dark variants where assets are added or changed.
2.**Fix reasoning icon**
- In `ReasoningView.kt`, change the reasoning header glyph from `SessionViewIcons.eye` to `SessionViewIcons.brain`.
- Add or update test coverage in `ReasoningViewTest.kt` by inspecting the rendered Swing label tree and asserting the reasoning icon is `SessionViewIcons.brain`.
3.**Normalize collapse/expand chevrons for session parts**
- Stop using the mixed `chevronRight`/`chevronDown` pair for collapsible session content.
- Use a single base Kilo chevron glyph for both states, matching the current custom chevron used by the session header (`/icons/chevron-down.svg` / equivalent `SessionViewIcons.chevronDown`).
- Add a shared rotated icon for the opposite state instead of switching to a differently sized right-facing asset. Prefer a small reusable helper or centralized icon field rather than importing header-specific UI into session views.
- Update `AbstractSessionPartView.kt` and `QuestionResultView.kt` to use the normalized chevron pair.
- Leave `QuestionView.kt` navigation chevrons alone unless auditing shows they are being used for collapse/expand; those are previous/next controls, not expand/collapse controls.
4.**Relocate and change header show/hide details toggle**
- In `SessionHeaderPanel.kt`, replace the custom header details chevron with platform `AllIcons` arrows/chevrons, e.g. collapsed = `AllIcons.General.ArrowRight`, expanded = `AllIcons.General.ArrowDown`.
- Move the details toggle out of the right-side controls and into `BorderLayout.WEST` of the header row.
- Rebuild the top header as:
- outer border layout
- west: details toggle button
- center: inner border layout
- inner center: session title
- inner east: horizontal stack/row with price/context and compact button
- Remove the details toggle from the right-side row so compaction remains visually separate from show/hide details.
- Keep existing tooltip/accessibility strings and expansion persistence behavior unchanged.
5.**Tests**
- Update `SessionHeaderPanelTest.kt` to assert:
- collapsed/expanded header details icons use the selected `AllIcons` constants;
- the details toggle persists expansion state as before;
- the details toggle is parented/laid out separately from the compact button.
- Update `AbstractSessionPartViewTest.kt` to assert collapsible parts keep the same icon dimensions across collapsed/expanded states and no longer use the mismatched right/down pair.
- Update `QuestionResultViewTest.kt` similarly because it has its own chevron implementation.
- Update `ReasoningViewTest.kt` for the brain icon.
6.**Verification**
- Run the smallest relevant JetBrains checks from `packages/kilo-jetbrains/`:
-`./gradlew test --tests "ai.kilocode.client.session.views.ReasoningViewTest" --tests "ai.kilocode.client.session.views.base.AbstractSessionPartViewTest" --tests "ai.kilocode.client.session.views.QuestionResultViewTest" --tests "ai.kilocode.client.session.ui.header.SessionHeaderPanelTest"`
-`./gradlew typecheck`
- If the filtered Gradle test syntax is not accepted by the project, run `./gradlew test` from `packages/kilo-jetbrains/` instead.
## Notes
- No shared upstream `opencode` files are involved; changes stay under `packages/kilo-jetbrains/`.
- A changeset may be needed because this is user-facing JetBrains UI polish; confirm existing changeset policy for the private JetBrains package during implementation.
description: Use when creating, triaging, or commenting on GitHub issues for the Kilo VS Code extension or JetBrains plugin via `gh`. Covers issue templates, project board assignment, title conventions, and required `gh` scopes.
---
# GitHub Issues
Use this skill whenever you create or manage a GitHub issue with `gh` for either the VS Code extension or the JetBrains plugin.
## Templates
The repo defines issue templates in `.github/ISSUE_TEMPLATE/`. Pick the matching template instead of opening a blank issue:
| Template | When to use |
|---|---|
| `Bug report` (`bug-report.yml`) | Reproducible defects with steps, expected, and actual behavior |
| `Feature Request` (`feature-request.yml`) | New capabilities, enhancements, or behavior changes |
| `Question` (`question.yml`) | Usage or design questions that aren't obviously bugs or feature requests |
Pass the template title to `gh issue create --template`.
## Title Conventions
- Use a plain, descriptive title that reads cleanly as a standalone sentence.
- Do not add platform-specific prefixes such as `[JetBrains]`, `[Jetbrains]`, `[JB]`, `[VS Code]`, `[VSCode]`, or similar. Routing happens through project boards, not the title.
## Project Boards
Every new issue must land on the correct project board:
If `gh` reports a missing scope when assigning a project, refresh the auth token and retry:
```bash
gh auth refresh -s project
```
After the refresh succeeds, re-run the original `gh issue create` command. Do not fall back to creating the issue without the project — the board assignment is required.
description: Use when changing shared upstream-owned files, editing or reviewing `kilocode_change` markers, or moving additive Kilo-specific behavior into Kilo-owned code to reduce future merge conflicts.
---
# Kilo Merge Minimizer
Use this skill whenever a normal development task touches shared upstream-owned code and includes Kilo-specific behavior, especially for marker cleanup, extraction work, or `kilocode_change` annotations.
Do not use this as the primary guide for upstream merge resolution. Upstream merges have their own instructions and should not duplicate that workflow here.
## Goal
Minimize Kilo's long-term diff against upstream OpenCode while preserving behavior.
Prefer this shape for Kilo-specific additions:
1. Shared upstream file contains only a minimal hook, import, call, registration, or config entry.
2. Kilo-specific behavior lives in Kilo-owned code.
3. Unavoidable shared-file changes have narrow `kilocode_change` markers.
4. The annotation checker passes.
For changes to existing upstream behavior, prefer the smallest in-place shared-file diff with narrow markers. Do not move changed upstream logic into Kilo-owned code just to avoid textual conflicts, because that can create harder semantic merge conflicts.
## Core Rules
- Use `script/check-opencode-annotations.ts` as the source of truth for current shared scopes and exempt paths.
- Use `script/upstream/fix-kilocode-markers.ts` for stale or broad markers, inspecting `--dry-run` output before applying changes.
- Treat upstream-owned files as shared unless the checker or repo ownership rules exempt them.
- Put Kilo-owned UI, CLI, runtime logic, and tests in Kilo-owned paths where practical.
- Avoid adding Kilo business logic directly to shared files.
- Keep shared-file edits as close as possible to upstream shape.
- Do not change shared files unless the change is required for Kilo functionality, fixes a Kilo bug, or is a minimal targeted upstream-quality fix.
- Do not create a large Kilo-only fork for a general upstream-quality improvement. Prefer a minimal targeted fix, or leave the broader change for upstream.
- Do not duplicate upstream logic unless there is a concrete reason. If duplication is unavoidable, isolate the Kilo delta and keep the upstream dependency obvious.
## Shared File Structure
- Do not refactor, rename, split files, or extract helpers in shared files just to improve readability or make Kilo extraction cleaner.
- Avoid structural changes that make upstream behavior harder to compare or hide semantic dependency on upstream code.
## Shared File Style
- Preserve upstream formatting and import style in shared files, even when it differs from Kilo style.
- Put Kilo-only imports on separate marked lines instead of reorganizing upstream imports.
## Decision Rules
Extract Kilo logic when:
- The change is an additive Kilo feature or integration, not a modification of existing upstream behavior.
- The shared-file change has meaningful Kilo-owned behavior, not just a tiny condition, import, registration, or field.
- The code has loops, branching, error handling, async workflows, storage access, network calls, UI rendering, or telemetry.
- The shared file can become a small orchestrator that calls Kilo helpers.
- The Kilo code is independent enough that extraction will not hide future upstream fixes or behavior changes.
Keep the change inline when:
- The Kilo delta is a single field, import, call, simple condition, or small registry entry.
- Extraction would reshape upstream code more than the Kilo change itself.
- The change modifies an upstream algorithm, ordering, heuristic, control flow, or bug fix.
- Extraction would duplicate upstream logic or hide semantic dependency on upstream behavior.
- The Kilo helper closes over upstream-local state. Keep closure-scoped helpers inline and contiguous in one narrow marker block.
- The shared file owns the only route table, enum, schema, switch, or registry where the hook must exist.
- The change restores upstream shape or removes a stale Kilo divergence.
Always preserve upstream behavior order unless the Kilo behavior change is intentional and tested.
## Marker Rules
- Mark only Kilo-specific diff lines in shared upstream files.
- Prefer inline markers for single-line changes: `const value = 42 // kilocode_change`.
- Use block markers only for adjacent Kilo-specific lines:
```ts
// kilocode_change start
registerKiloFeature(app)
// kilocode_change end
```
- Use the file's native comment style, including JSX block comments inside JSX and `#` comments for YAML, TOML, and shell.
- Do not add markers in checker-exempt Kilo-owned paths.
- Remove stale markers when upstream already contains the behavior or when touching Kilo-owned files that still have old markers.
- Use `// kilocode_change - new file` only for unavoidable new Kilo-specific files inside shared upstream paths.
## Tests
- Put Kilo-specific CLI/runtime tests in Kilo-owned test paths.
- Move tests out of shared upstream test paths when the behavior under test is Kilo-specific.
- Tests should cover the real failing path, not private or unstable APIs chosen only for convenience.
- Do not add skip gates for required regression coverage.
## Verification
After editing shared files or marker comments, run:
```bash
bun run script/check-opencode-annotations.ts
```
If the PR uses a non-default comparison base, pass the correct base ref:
```bash
bun run script/check-opencode-annotations.ts --base <base-ref>
```
For stale or broad markers in one shared file, inspect the dry run before applying:
```bash
bun run script/upstream/fix-kilocode-markers.ts <repo-relative-file> --dry-run
description: Use when releasing the Kilo JetBrains plugin -- resolve a version ("next rc" or explicit), run the prepare workflow, edit and commit a filtered human-readable changelog on the release PR, then watch publish to completion.
---
# JetBrains Release
Use this skill when releasing the Kilo JetBrains plugin.
This skill drives the existing JetBrains release workflows. It must not move, delete, or recreate JetBrains release tags. It must always confirm the resolved version with the user before dispatching the prepare workflow because the prepare workflow creates an immutable `jetbrains/v<version>` tag.
## Preconditions
- Run from the repository root.
-`gh` must be authenticated for `Kilo-Org/kilocode` with permission to dispatch workflows, read PRs, and write contents. Merge permission is only required if the user asks the skill to merge the release PR automatically.
- Check auth with `gh auth status`. For GitHub CLI OAuth, refresh common release scopes with `gh auth refresh -s repo -s workflow`; `repo` covers private-repo contents and PR operations, and `workflow` allows workflow dispatch. If using a fine-grained token instead, grant repository permissions for Actions read/write, Contents read/write, and Pull requests read/write. Merging still requires normal repository collaborator permission or a token/user allowed by branch protection.
- Reference `packages/kilo-jetbrains/RELEASING.md` for manual recovery rules.
- Do not locally check out the generated release branch. The helper scripts update the release branch through GitHub to avoid disturbing the current worktree.
## Version Resolution
Resolve the user's version request:
```bash
bun .kilo/skills/release-jetbrains/script/resolve-version.ts --spec "next rc"
```
Accepted specs:
| Spec | Meaning |
|---|---|
| `next rc` | If the latest JetBrains tag is an RC, increment its `rc.n`; otherwise start the next patch RC at `rc.1`. |
| `next stable` | If the latest JetBrains tag is an RC, use its base version; otherwise use the next patch stable. |
| `x.y.z-rc.n` | Explicit RC release. |
| `x.y.z` | Explicit stable release. |
Show the resolved `version`, `kind`, and default `fromTagDefault` to the user and ask for confirmation before continuing.
## Prepare Workflow
After confirmation, dispatch and watch the prepare workflow:
```bash
bun .kilo/skills/release-jetbrains/script/dispatch-prepare.ts --kind rc --version 7.0.1-rc.7
```
Pass a generous Bash timeout, such as `1800000` ms, because the script blocks on `gh run watch --exit-status`. If the shell times out but the workflow is still running, re-attach with:
```bash
bun .kilo/skills/release-jetbrains/script/dispatch-prepare.ts --kind rc --version 7.0.1-rc.7 --run-id <run-id>
```
The script prints `prNumber`, `prUrl`, `runUrl`, and `branch` on success. Immediately show the `prUrl` to the user so they can open the release PR without asking for it later.
## Changelog Draft
Create a changelog draft after the prepare PR exists:
1. Read the PR body with `gh pr view <pr> --json body`.
2. Extract `JetBrains-From-Tag`, `JetBrains-Tag`, and `## Generated Notes`.
3. Fetch the release range tags if they are missing locally:
Keep JetBrains and CLI/runtime changes. Drop unrelated VS Code, docs, gateway, telemetry, i18n, desktop, and webview-only changes unless they affect the CLI bundled into the JetBrains plugin.
Rewrite terse commit or PR titles into user-facing bullets grouped under `### Added`, `### Fixed`, and `### Changed`. Keep the exact generated header format:
Ask the user to edit the file and confirm when done.
## Commit Changelog
After the user confirms the draft is ready, strip the `<!-- CONTEXT ... -->` block into a temporary cleaned file, then commit the cleaned section to the release branch:
```bash
bun .kilo/skills/release-jetbrains/script/update-changelog.ts --version 7.0.1-rc.7 --file /path/to/clean-section.md
```
The script updates `packages/kilo-jetbrains/CHANGELOG.md` on `jetbrains/release/v<version>` through the GitHub contents API and commits with:
```text
docs(jetbrains): edit changelog for v<version>
```
If `update-changelog.ts` fails with `gh: Not Found (HTTP 404)`, verify the release branch and changelog path with:
```bash
gh api "repos/Kilo-Org/kilocode/contents/packages/kilo-jetbrains/CHANGELOG.md?ref=jetbrains/release/v<version>"
```
Then either fix and retry the helper, or perform the equivalent contents API update using `ref` in the query string.
After the changelog commit succeeds, show the release PR URL again and tell the user that the PR needs manual approval and merge before publishing can continue.
## Approve And Publish
Ask the user to approve the release changelog and metadata. Before merging or publishing, verify the PR approval and required checks are green:
Do not merge or publish while required checks are failing unless the user explicitly gives a maintainer override.
If a required check fails from an apparent flake, rerun only the failed jobs and wait for the run to finish:
```bash
gh run rerun <run-id> --failed
gh run watch <run-id> --exit-status
```
By default, have the user merge the release PR manually in GitHub, then watch the publish workflow:
```bash
bun .kilo/skills/release-jetbrains/script/watch-publish.ts --pr <number> --version 7.0.1-rc.7
```
Only merge automatically when the user explicitly asks for it and `gh` has merge permission:
```bash
bun .kilo/skills/release-jetbrains/script/watch-publish.ts --pr <number> --version 7.0.1-rc.7 --merge
```
Pass a generous Bash timeout, such as `1800000` ms. If the shell times out, re-attach with:
```bash
bun .kilo/skills/release-jetbrains/script/watch-publish.ts --pr <number> --version 7.0.1-rc.7 --run-id <run-id>
```
If `watch-publish.ts --merge` reports that the PR is already merged, or a transient GitHub API `5xx` interrupts publish-run discovery, rerun without `--merge`:
```bash
bun .kilo/skills/release-jetbrains/script/watch-publish.ts --pr <number> --version <version>
```
Report the Marketplace channel and GitHub Release URL. RC versions publish to the `eap` channel; stable versions publish to the default Marketplace channel.
## Recovery
- If prepare created the tag but failed before creating a PR, rerun prepare for the same version. The existing workflow reuses the tag if it points to the same commit.
- If a tag points to an unexpected SHA, stop and inspect manually. Do not move or delete release tags casually.
- If release PR checks fail from an apparent flake, use `gh run rerun <run-id> --failed`, then `gh run watch <run-id> --exit-status` before publishing.
- If publish fails after merge, rerun the failed workflow only if Marketplace did not already accept the version.
- If Marketplace succeeds but GitHub Release upload fails, manually create or edit the GitHub Release for `jetbrains/v<version>` using the reviewed changelog.
@@ -14,95 +14,38 @@ Use your github-triage tool to triage issues.
This file is the source of truth for ownership/routing rules.
## Labels
Assign issues by choosing the team with the strongest overlap. The github-triage tool will assign a random member from that team.
### windows
Do not add labels to issues. Only assign an owner.
Use for any issue that mentions Windows (the OS). Be sure they are saying that they are on Windows.
When calling github-triage, pass one of these team values: tui, desktop_web, core, inference, windows, jetbrains, extension
- Use if they mention WSL too
## Teams
#### perf
### TUI
Performance-related issues:
Terminal UI issues, including rendering, keybindings, scrolling, terminal compatibility, SSH behavior, crashes in the TUI, and low-level TUI performance.
- Slow performance
- High RAM usage
- High CPU usage
### Desktop / Web
**Only** add if it's likely a RAM or CPU issue. **Do not** add for LLM slowness.
Desktop application and browser-based app issues, including `opencode web`, desktop-specific UI behavior, packaging, and web view problems.
#### nix
### Core
**Only** add if the issue explicitly mentions nix.
Core opencode server and harness issues, including sqlite, snapshots, memory, API behavior, agent context construction, tool execution, provider integrations, model behavior, documentation, and larger architectural features.
If the issue does not mention nix, do not add nix.
### Inference
If the issue mentions nix, assign to `catrielmuller`.
Kilo Provider, Provider implementation, and billing issues.
#### core
### Windows
Use for core server issues in`packages/opencode/`, excluding `packages/opencode/src/cli/cmd/tui/`.
Windows-specific issues, including native Windows behavior, WSL interactions, path handling, shell compatibility, and installation or runtime problems that only happen on Windows.
Examples:
### Jetbrains
- LSP server behavior
- Harness behavior (agent + tools)
- Feature requests for server behavior
- Agent context construction
- API endpoints
- Provider integration issues
- New, broken, or poor-quality models
Jetbrains extension related issues.
#### vscode
### Extension
Use for issues related to the VSCode extension in `packages/kilo-vscode/`.
#### gateway
Use for issues related to the Kilo Gateway in `packages/kilo-gateway/`.
When assigning to people here are the following rules:
Nix:
ONLY assign if the issue will have the "nix" label.
- catrielmuller
Models / Providers:
Use for issues about model quality, provider integrations, or broken/new models.
- chrarnoldus
Cloud Agents:
Use for issues about cloud agent behavior or infrastructure.
- pandemicsyn
- eshurakov
Core (`packages/opencode/...`):
- kevinvandijk
- marius-kilocode
- catrielmuller
VSCode Extension (`packages/kilo-vscode/...`):
- markijbema
Kilo Gateway (`packages/kilo-gateway/...`):
- jrf0110
Windows:
- catrielmuller (assign any issue that mentions Windows or is likely Windows-specific)
Determinism rules:
- If "nix" label is added but title + body does not mention nix/nixos, the tool will drop "nix"
- If title + body mentions nix/nixos, assign to `catrielmuller`
- If "vscode" label is added, assign to `markijbema`
- If "gateway" label is added, assign to `jrf0110`
In all other cases, choose the team/section with the most overlap with the issue and assign a member from that team at random.
description: Answer questions about the Effect framework
description: Work with Effect v4 / effect-smol TypeScript code in this repo
---
# Effect
This codebase uses Effect, a framework for writing typescript.
This codebase uses Effect for typed, composable TypeScript services, schemas, and workflows.
## How to Answer Effect Questions
## Source Of Truth
1. Clone the Effect repository: `https://github.com/Effect-TS/effect-smol` to
`.opencode/references/effect-smol` in this project NOT the skill folder.
2. Use the explore agent to search the codebase for answers about Effect patterns, APIs, and concepts
3. Provideresponses based on the actual Effect source code and documentation
Use the current Effect v4 / effect-smol source, not memory or older Effect v2/v3 examples.
1. If `.opencode/references/effect-smol` is missing, clone `https://github.com/Effect-TS/effect-smol` there. Do this in the project, not in the skill folder.
2. Search `.opencode/references/effect-smol` for exact APIs, examples, tests, and naming patterns before answering or implementing Effect-specific code.
3. Also inspect existing repo code for local house style before introducing new patterns.
4. Prefer answers and implementations backed by specific source files or nearby repo examples.
## Guidelines
-Always use the explore agent with the cloned repository when answering Effect-related questions
-Reference specific files and patterns found in the Effect codebase
-Do not answer from memory - always verify against the source
-Prefer current Effect v4 APIs and project-local patterns over old blog posts, examples, or package-memory guesses.
-Use `Effect.gen(function* () { ... })` for multi-step workflows.
-Use `Effect.fn("Name")` or `Effect.fnUntraced(...)` for named effects when adding reusable service methods or important workflows.
- Prefer Effect `Schema` for API and domain data shapes. Use branded schemas for IDs and `Schema.TaggedErrorClass` for typed domain errors when modeling new error surfaces.
- Keep HTTP handlers thin: decode input, read request context, call services, and map transport errors. Put business rules in services.
- In Effect service code, prefer Effect-aware platform abstractions and dependencies over ad hoc promises where the surrounding code already does so.
- Keep layer composition explicit. Avoid broad hidden provisioning that makes missing dependencies hard to see.
- In tests, prefer the repo's existing Effect test helpers and live tests for filesystem, git, child process, locks, or timing behavior.
- Do not introduce `any`, non-null assertions, unchecked casts, or older Effect APIs just to satisfy types.
- Do not answer from memory. Verify against `.opencode/references/effect-smol` or nearby code first.
## Testing Patterns
- Use `testEffect(...)` from `packages/opencode/test/lib/effect.ts` for tests that exercise Effect services, layers, runtime context, scoped resources, or platform integrations.
- Use `it.live(...)` for filesystem, git repositories, HTTP servers, sockets, child processes, locks, real time, and other live platform behavior.
- Run tests from package directories such as `packages/opencode`; never run package tests from the repo root.
- Prefer explicit test layers over ad hoc managed runtimes. Keep dependency provisioning visible in the test file.
- Use scoped fixtures and finalizers for resources that must be cleaned up, including temporary directories, flags, databases, fibers, servers, and global state.
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.