Compare commits

...

179 Commits

Author SHA1 Message Date
Mark IJbema 6f08110d4d Merge pull request #593 from Kilo-Org/markijbema-patch-1
Check Links / link-checker (push) Has been cancelled
add redirect to readme
2026-02-22 16:30:31 +01:00
Mark IJbema d1e4844fbf Revise README with updated information and links
Updated README to reflect new links and features for Kilo.
2026-02-22 16:30:01 +01:00
Mark IJbema bf8064ddc4 Merge pull request #546 from Kilo-Org/session/agent_8e672607-eb9d-4b31-8292-c18813a7a18d
fix(vscode): fix caret position desync after pasting text in chat input
2026-02-22 12:44:48 +01:00
Mark IJbema bbcf5f1aec Merge pull request #582 from Kilo-Org/fix-manifest-icon
Add proper details to vscode marketplace manifest
2026-02-22 11:19:16 +01:00
Mark IJbema 89876b43b1 Merge pull request #584 from pschiel/vscode-ext-windows-fix
fix: use kilo.exe as binary name on win32
2026-02-22 11:17:29 +01:00
kilo-maintainer[bot] d3411035d8 chore: generate 2026-02-22 03:20:10 +00:00
Brendan O'Leary 6238d69043 Merge pull request #576 from Kilo-Org/docs/broken-links-checker 2026-02-21 22:19:24 -05:00
ops 21ecdf5dc2 fix: use kilo.exe as binary name on win32 2026-02-22 01:11:52 +01:00
Kevin van Dijk f7c4f41b4b Add correct title and description 2026-02-22 00:45:54 +01:00
Kevin van Dijk 9aa32abe7b Add proper logo to vscode marketplace manifest 2026-02-22 00:41:09 +01:00
Brendan O'Leary 0619ad125c Update packages/kilo-docs/pages/collaborate/index.md
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-02-21 15:23:54 -05:00
Brendan O'Leary 36e41096ec Update packages/kilo-docs/pages/collaborate/index.md
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-02-21 15:23:40 -05:00
Brendan O'Leary 2379bf0836 Update packages/kilo-docs/pages/collaborate/index.md
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-02-21 15:23:34 -05:00
Brendan O'Leary b212edcc21 Update packages/kilo-docs/pages/collaborate/index.md
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
2026-02-21 15:23:27 -05:00
Brendan O'Leary a6b569a4aa Update working Directory for docs check 2026-02-21 15:23:08 -05:00
Brendan O'Leary 8744ff5645 Fix all internal links 2026-02-21 15:21:07 -05:00
Brendan O'Leary a46770079d Update some internal links 2026-02-21 14:44:04 -05:00
Brendan O'Leary d30b20de6b Add lychee link checker to docs 2026-02-21 14:27:20 -05:00
Brendan O'Leary 1a455945bc Merge pull request #563 from Kilo-Org/docs/fix-navigation-weirdness 2026-02-21 11:56:07 -05:00
kilo-maintainer[bot] 4093d575c1 release: v1.0.25 2026-02-21 13:04:22 +00:00
Brendan O'Leary 5bc453db7e Merge pull request #562 from Kilo-Org/docs/add-raw-markdown-links-to-llms-txt 2026-02-21 06:59:35 -05:00
Brendan O'Leary d2cca11144 Merge pull request #477 from Olusammytee/docs/2154-update-custom-instruction-files-docs 2026-02-21 06:56:10 -05:00
Brendan O'Leary 854005e16d Fix navigation issue with sidenav 2026-02-21 06:55:33 -05:00
Brendan O'Leary 6e3c429be5 Merge pull request #559 from maphew/fix/contributing-broken-link 2026-02-21 06:53:37 -05:00
Brendan O'Leary eef24bb5ff Merge branch 'dev' into docs/2154-update-custom-instruction-files-docs 2026-02-21 06:52:47 -05:00
Brendan O'Leary 6701f014e9 Merge pull request #481 from Olusammytee/docs/2147-clarify-custom-modes-yaml-v2
docs: clarify YAML-first custom modes behavior
2026-02-21 06:51:06 -05:00
Brendan O'Leary d2c11bd641 Add raw markdown links to LLMs.txt 2026-02-21 06:44:31 -05:00
Brendan O'Leary be120b5eec Merge branch 'dev' into docs/2147-clarify-custom-modes-yaml-v2 2026-02-21 06:34:24 -05:00
Brendan O'Leary 772b8689b2 Merge pull request #476 from Olusammytee/docs/5619-clarify-cloud-setup-script-behavior
docs(cloud-agent): clarify Setup Commands vs .kilocode/setup-script
2026-02-21 06:32:10 -05:00
Brendan O'Leary 764a642a2e Merge branch 'dev' into docs/5619-clarify-cloud-setup-script-behavior 2026-02-21 06:29:02 -05:00
maphew 2ac737ceba fix(docs): remove broken sidebar nav links for annual-billing and memory-bank
Fixes #545
2026-02-20 23:32:10 -07:00
maphew d703ee482f fix: update broken contributing docs link in CONTRIBUTING.md
Fixes #465
2026-02-20 23:29:36 -07:00
Marius 6b610bb9a2 fix(agent-manager): add missing NotificationsProvider to provider chain (#551)
The notifications merge (PR #437) added KiloNotifications to ChatView and
NotificationsProvider to the sidebar App.tsx but missed the Agent Manager's
AgentManagerApp.tsx. When ChatView renders inside the Agent Manager, the
useNotifications() call throws because there is no provider — silently
crashing the component tree via SolidJS error boundaries and preventing
session tabs from rendering.
2026-02-20 21:21:55 +00:00
kiloconnect[bot] 35008ef4b5 fix(vscode): recalculate textarea layout after paste to fix caret position
After pasting a large body of text into the chat input, the textarea
height wasn't being recalculated in time, causing the caret position
to visually desync from its actual position.

Add a handlePaste wrapper that defers adjustHeight() and
syncHighlightScroll() via requestAnimationFrame, ensuring the browser
has completed the reflow before recalculating dimensions.
2026-02-20 18:17:26 +00:00
Catriel Müller b39006f562 Merge pull request #125 from pschiel/question-tool-description
fix: add length constraint in question tool prompt
2026-02-20 14:18:35 -03:00
Igor Šćekić 2f394242ad Merge pull request #542 from Kilo-Org/feat/172-toggle-thinking
feat(vscode): add thinking effort toggle to prompt input
2026-02-20 18:14:21 +01:00
Catriel Müller e909f207f1 Merge branch 'dev' into question-tool-description 2026-02-20 14:14:05 -03:00
Catriel Müller d475be7662 Merge pull request #543 from Kilo-Org/catrielmuller/skip-inconsistente-2e-test
refactor: skip internmitent e2e test
2026-02-20 14:13:51 -03:00
Igor Šćekić 7c6a526b7e refactor(vscode): remove undefined from variant persistence types 2026-02-20 18:08:03 +01:00
Igor Šćekić d66054e958 refactor(vscode): remove Default option from thinking selector
First variant from the provider is implicitly the default.
selectVariant now only accepts string values.
2026-02-20 18:06:45 +01:00
Catriel Müller a06c331017 refactor: skip internmitent e2e test 2026-02-20 14:05:44 -03:00
Igor Šćekić 4f9f7c3483 refactor(vscode): replace thinking cycle button with popover dropdown
Replaces the single cycle button with a ThinkingSelector popover
component matching the ModeSwitcher pattern. Lists all available
variants plus a Default option to disable thinking.
2026-02-20 18:02:22 +01:00
Catriel Müller aac2685e92 Merge branch 'dev' into question-tool-description 2026-02-20 13:55:15 -03:00
Igor Šćekić 1416ebc174 feat(vscode): add thinking effort toggle to prompt input
Adds a variant cycle button to the VS Code extension's prompt input
that lets users toggle the thinking effort level (e.g. high/max) for
models that support reasoning, matching the TUI app behaviour.

- Extend ProviderModel types to expose variants and capabilities.reasoning
- Thread variant through the full send-message pipeline (webview → extension → CLI)
- Persist variant selections via VS Code globalState
- Render a thinking toggle button next to the model selector (only
  visible when the selected model supports reasoning variants)

Closes #172
2026-02-20 17:42:27 +01:00
Marian Alexandru Alecu c7c401a55b Merge pull request #520 from Kilo-Org/fix/fix-orphan-sub-agents
fix: Close sub-agents, preventing them from becoming orphan processes
2026-02-20 18:14:37 +02:00
Igor Šćekić b6739440af Merge pull request #528 from Kilo-Org/feat/349-permission-session-hint
feat(vscode): add session-lifetime hint to permission auto-approve dialog
2026-02-20 17:14:02 +01:00
Marius 993ba69c0e feat(vscode): add Cmd+Shift+M keybinding to open Agent Manager (#511) 2026-02-20 13:13:15 -03:00
Marius 309bcaa297 feat(agent-manager): non-blocking worktree setup with unified busy state (#532)
Show new worktrees in the sidebar immediately after creation with a
spinner icon, allowing users to switch to other worktrees while the
setup script runs instead of being blocked by a full-screen overlay.

- Add worktreeId to worktreeSetup messages so the webview can track
  which worktree each setup event belongs to
- Push state to sidebar immediately after git worktree creation so the
  entry appears before the setup script runs
- Replace separate deletingWorktrees/settingUpWorktrees signals with a
  unified busyWorktrees map (WorktreeBusyState with reason field) for
  consistent loading behavior across setup and deletion
- Scope the setup overlay to only show when the setting-up worktree is
  selected; switching away hides it, switching back restores it
- Hide the delete button on busy worktrees instead of showing a second
  spinner
- Ensure failed session creation cleans up stale sidebar entries via
  pushState() after removeWorktree()
2026-02-20 16:10:54 +00:00
Catriel Müller e2e4520be3 Merge pull request #538 from Kilo-Org/fix/remove-redundant-copy-button
fix(ui): remove redundant copy button from TextPartDisplay
2026-02-20 13:10:23 -03:00
Igor Šćekić 72e9bd2ec1 Merge pull request #479 from Kilo-Org/feat/clickable-filenames-461-404
feat(vscode): make filenames in chat clickable to open editor tab
2026-02-20 17:07:36 +01:00
Marius 594fb4b5d6 fix(vscode): prevent UI blocking when switching sessions rapidly (#533)
* fix(vscode): prevent UI blocking when switching sessions rapidly

- Show loading spinner in MessageList during session switch instead of blank screen
- Fire handleLoadMessages without await so rapid switches aren't serialized
- Abort stale getMessages requests via AbortController when switching away
- Scope error messages with sessionID so stale 404s don't clear wrong session's loading state
- Silence expected 404s on cross-worktree getSession calls via silent HTTP option

* fix: replace empty catch block with warning log for getSession errors
2026-02-20 16:05:15 +00:00
Marius 485fa9db52 fix(agent-manager): resolve sessionsLoaded race condition with webview mount (#539)
The loading skeleton gates (worktreesLoaded && sessionsLoaded) could
permanently block the Agent Manager UI. initializeState() called
refreshSessions() which sent sessionsLoaded before the webview's
onMount handlers registered, so the signal was lost. Since sessions
were already populated, the MessageList backup effect never triggered
a retry.

Add refreshSessions() to the requestState handler which fires from
the webview's onMount, guaranteeing all message listeners are ready.
2026-02-20 16:02:29 +00:00
Catriel Müller 8dcc40f01b refactor: simplify pr 2026-02-20 12:55:17 -03:00
Halil İbrahim ceylan cb5e3cea23 refactor(ui): remove unused text part copy wrapper styles 2026-02-20 12:55:17 -03:00
Marian Alexandru Alecu 8ddabbf84a Merge branch 'dev' into fix/fix-orphan-sub-agents 2026-02-20 17:52:59 +02:00
Marius c520e4523a fix(agent-manager): add am- prefix to prompt-input CSS classes (#535)
The agent-manager-arch test enforces that all CSS class selectors in
agent-manager.css use the am- prefix. The NewWorktreeDialog was reusing
unprefixed prompt-input-* classes from the sidebar chat CSS, which
violated this rule and broke the test-vscode CI pipeline.
2026-02-20 15:48:50 +00:00
Igor Šćekić 043c37ab7e Merge pull request #531 from Kilo-Org/fix/vscode-notification-absolute-position
fix(vscode): absolutely position notification bar to not push content down
2026-02-20 16:44:09 +01:00
Marius 3b7d0721f3 fix(agent-manager): reset stale body styles when webview regains focus (#530)
Kobalte modal dropdowns set pointer-events:none and overflow:hidden on
document.body. When the user opens the setup script editor from the
settings dropdown, VS Code steals focus before the dropdown cleanup
runs, leaving the body permanently unclickable. Clear these stale
styles in the existing window focus handler so the UI recovers when
the user returns to the agent manager tab.
2026-02-20 16:40:09 +01:00
Marius 57ea8f1185 fix(agent-manager): show "not a git repository" instead of infinite loading spinner (#529)
When the Agent Manager opens in a non-git folder, initializeState()
returned early without pushing state to the webview, leaving the
skeleton loader spinning forever. Now pushes empty state with
isGitRepo: false so the UI can display a clear message and hide
worktree action buttons.
2026-02-20 16:39:06 +01:00
Alex Alecu a514530139 fix: ensure abort fires even if shutdown throws in web.ts
Wrap Instance.disposeAll() and server.stop() in try/finally so
abort.abort() always fires, preventing the process from hanging
if either call rejects.
2026-02-20 17:38:40 +02:00
Alex Alecu 7f94b83893 fix: ensure abort fires even if shutdown throws in serve.ts
Wrap Instance.disposeAll() and server.stop() in try/finally so
abort.abort() always fires, preventing the process from hanging
if either call rejects.
2026-02-20 17:38:35 +02:00
Igor Šćekić 29a6495d88 Merge pull request #521 from Kilo-Org/add-vscode-tests
add extension tests
2026-02-20 16:01:58 +01:00
Catriel Müller f2b60c81dd Merge pull request #454 from haliliceylan/fix-406
fix(ui): show horizontal scrollbar on code blocks in markdown
2026-02-20 11:46:05 -03:00
Igor Šćekić 00fa743efa fix(vscode): absolutely position notification bar to not push content down 2026-02-20 15:43:51 +01:00
Brendan O'Leary 8401ff4b70 Merge pull request #500 from Kilo-Org/florian/docs/changelog
Add quick docs for KiloClaw's changelog
2026-02-20 09:41:35 -05:00
Igor Šćekić 776402da13 fix: correct translation mismatches and add hint to message-part.tsx permission prompts
- Fix quoted button label in br, pl, ru, zht to match their allowAlways values
- Add permission-hint to both permission prompt locations in message-part.tsx
2026-02-20 15:38:47 +01:00
Igor Šćekić 43ae6b2425 feat(vscode): add session-lifetime hint to permission auto-approve dialog
Clarifies that 'Allow always' only applies for the duration of the current
session, not globally. Adds translated hint text below the permission
action buttons in all supported locales.
2026-02-20 15:27:42 +01:00
Catriel Müller c66c3118c3 Merge pull request #437 from Kilo-Org/catrielmuller/320-notifications-vscode
feat(vscode): add Kilo notifications banner to VS Code extension
2026-02-20 11:11:40 -03:00
Marius 0d1a1e1c2a feat(agent-manager): multi-version worktree creation (#525)
* tmp

* feat(agent-manager): add multi-version worktree creation with grouping and loading states

* feat(agent-manager): reuse prompt-input UI in dialog, fix model/agent persistence, polish

* fix(agent-manager): restore Tooltip import lost during merge, fixing dialog open

* fix(agent-manager): address PR review — validate msg.text, remove dead labels, run setup script for multi-version worktrees

* fix(agent-manager): address PR review round 2 — error notification, remove dead code, type extension messages, fix loading race condition
2026-02-20 15:09:14 +01:00
Marius 9fbfb7ec34 feat(agent-manager): add keyboard shortcuts dialog to settings menu (#524)
Add a Keyboard Shortcuts item to the settings gear dropdown in the
Agent Manager sidebar. Opens a kilo-ui Dialog showing all available
shortcuts grouped by category (Sidebar, Tabs, Terminal, Global) with
platform-appropriate key rendering (Mac symbols / Windows key names).

Also exposes the global agentManagerOpen keybinding so it appears in
the dialog alongside the agent-manager-scoped shortcuts.
2026-02-20 15:08:05 +01:00
Marius daee6b292e feat(agent-manager): collapsible sessions section with persisted state (#522)
Make the SESSIONS header in the Agent Manager sidebar clickable to
collapse/expand the session list. When collapsed, the worktrees section
takes the full vertical space. The collapsed state is persisted to
.kilocode/agent-manager.json so it survives VS Code restarts.
2026-02-20 15:07:04 +01:00
Marius a471173c9b test(agent-manager): improve test coverage for provider routing, concurrent saves, and terminal manager (#527)
Add 23 new tests across 4 files covering previously untested code paths:

- AgentManagerProvider: static-analysis tests for message routing, ordering
  constraints (setup before session, state before ready), cleanup on failure
- WorktreeStateManager: concurrent save serialization, corrupt/partial JSON
- WorktreeManager: branch collision retry path, safety guard for removals
- SessionTerminalManager: new test file for structural invariants (exit
  cleanup ordering, CWD fallback, context key lifecycle)
2026-02-20 15:06:22 +01:00
Marius ed34c9f010 fix(agent-manager): dismiss setup overlay on script error (#523)
The catch block in runSetupScriptForWorktree only logged to the output
channel but never posted a status error to the webview. Since the setup
overlay only dismisses on ready or error status, any exception during
script execution left the overlay covering the entire UI permanently.
2026-02-20 15:00:38 +01:00
Marius 03e6adaaec fix(vscode): route focusChatInput (Cmd+Shift+A) to active panel (#526)
* fix(vscode): route focusChatInput (Cmd+Shift+A) to active panel

The focusChatInput command was hardcoded to always target the sidebar
KiloProvider. When the Agent Manager panel was focused, the shortcut
had no effect. Now the command checks which panel is active at
invocation time and routes the message accordingly.

* fix(vscode): route addToContext setChatBoxMessage through target() too

Both setChatBoxMessage and focusInput in the addToContext handler now
use target() so the context text and focus always go to the same panel.
2026-02-20 15:00:17 +01:00
Catriel Müller 85aeb6f6a6 refactor: fix undefined 2026-02-20 10:59:57 -03:00
Catriel Müller 9fb453a9af refactor: add console to catch 2026-02-20 10:59:57 -03:00
Catriel Müller 3a0ef619ed refactor: prune old notifications 2026-02-20 10:59:57 -03:00
Catriel Müller aa52b851fd Merge branch 'dev' into catrielmuller/320-notifications-vscode 2026-02-20 10:59:50 -03:00
kilo-maintainer[bot] 6b9f23ff00 chore: generate 2026-02-20 13:54:12 +00:00
Marian Alexandru Alecu b3eab31a54 Merge pull request #459 from Kilo-Org/feat/suggestions-after-plan-end 2026-02-20 15:53:12 +02:00
Marian Alexandru Alecu 6337e0d517 Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-20 15:28:35 +02:00
Igor Šćekić 71a0187412 style(vscode): format telemetry-proxy-utils test 2026-02-20 14:23:24 +01:00
Igor Šćekić 48f4dc49ce style(vscode): format permission-queue test 2026-02-20 14:23:19 +01:00
Igor Šćekić 0c691460e9 style(vscode): format chat-autocomplete-utils test 2026-02-20 14:23:13 +01:00
Igor Šćekić 40e5cd57ac test(vscode): extract toggleAnswer, buildSubtitleText from QuestionDock and add tests 2026-02-20 14:16:28 +01:00
Igor Šćekić 582566f3ec test(vscode): extract fileName, dirName, buildHighlightSegments from PromptInput and add tests 2026-02-20 14:15:14 +01:00
Igor Šćekić 5808ab0042 test(vscode): extract providerSortKey, isFree, buildTriggerLabel from ModelSelector and add tests 2026-02-20 14:13:54 +01:00
Igor Šćekić 92f5c74f20 test(vscode): strengthen formatTime and postprocessAutocompleteSuggestion assertions 2026-02-20 13:42:59 +01:00
Igor Šćekić b1d5fa104f test(vscode): add generateQRCode tests for data URL output and error on empty input 2026-02-20 13:41:51 +01:00
Igor Šćekić 1bad5eb067 test(vscode): add code-action-provider tests for action set and command IDs 2026-02-20 13:40:57 +01:00
Igor Šćekić bc3bb46aa0 fix(vscode): log warning in parseSSEDataLine catch instead of empty catch block 2026-02-20 13:39:39 +01:00
Marius 2d2699f072 feat(vscode): add loading skeletons for Agent Manager sessions and worktrees (#518)
* feat: add loading skeletons for agent manager sessions and worktrees

Add skeleton loading states to the Agent Manager sidebar so users see
pulsing placeholders while worktrees and sessions load from the backend.

- Track worktreesLoaded/sessionsLoaded signals in the webview
- Add agentManager.requestState message so the webview can pull state
  on mount (fixes race where initial pushState fires before mount)
- Await stateReady in the extension before responding to requestState
  (ensures JSON is loaded from disk before sending data)
- Mark sessions loaded from both agentManager.state and sessionsLoaded
  message paths for consistent behavior
- Add skeleton CSS with staggered pulse animations

* fix: gate worktree list on sessionsLoaded to prevent branch name flash

The worktreeLabel() function falls back to wt.branch (e.g. kilo-...)
when session data hasn't arrived yet. Gate the worktree list render
on both worktreesLoaded and sessionsLoaded so the skeleton stays
visible until session titles are available.

- Listen for sessionsLoaded message directly instead of watching
  session.sessions() length (handles empty session lists too)
- Remove premature sessionsLoaded=true from agentManager.state handler
  since that message only carries IDs, not session titles

* fix: make skeleton shapes match actual worktree/session item layout

Worktree skeleton: single row with branch icon placeholder + text bar,
matching the .am-worktree-item padding (10px) and gap (8px).

Session skeleton: title bar + timestamp bar on the right, matching
the .am-item layout with justify-content: space-between, padding
(6px 10px), and smaller font size for the time placeholder.

* fix: add .catch() to requestState handler to prevent unhandled rejection

If initializeState() rejects, pushState() still fires with whatever
state is available (empty arrays), so skeletons resolve to the empty
state instead of loading forever.

* fix: log error in requestState catch handler per style guide
2026-02-20 12:39:21 +00:00
Igor Šćekić b1ff1d607a fix(vscode): use parseAutocompleteResponse util in HoleFiller.getFromChat 2026-02-20 13:39:03 +01:00
Igor Šćekić 7fc37ca2e3 fix(vscode): remove unused buildTextAfterMentionSelect import in useFileMention 2026-02-20 13:38:08 +01:00
Igor Šćekić 5bdcd646bc ci(vscode): add unit test script and CI workflow with path filter 2026-02-20 13:37:36 +01:00
Catriel Müller bb713c7c8c Merge branch 'dev' into fix-406 2026-02-20 09:34:46 -03:00
Marian Alexandru Alecu 2943ef75fe Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-20 14:32:45 +02:00
Alex Alecu 1378c57501 Merge branch 'feat/suggestions-after-plan-end' of github.com:Kilo-Org/kilo into feat/suggestions-after-plan-end 2026-02-20 14:31:03 +02:00
Marius cb18296f88 feat(agent-manager): add keyboard shortcut tooltips and worktree hover cards (#516)
* feat(agent-manager): add keyboard shortcut tooltips and worktree hover cards

- Add TooltipKeybind to all agent manager buttons (tabs, new session,
  close tab, terminal, new worktree, delete worktree, promote to worktree)
- Add HoverCard popovers on worktree items showing branch name, base
  branch, session count, creation date, and navigation shortcut hint
- Show directional keybind hints only for directly adjacent items
  (tabs: ⌘←/⌘→, worktrees: ⌘↑/⌘↓)
- Resolve keybindings from package.json at runtime per platform
  (Mac symbols vs Windows/Linux Ctrl+key format)
- Send resolved keybindings from extension to webview via new
  agentManager.keybindings message instead of hardcoding shortcuts
- Prevent multiple HoverCards from appearing simultaneously via
  shared hover state lifted above the For loop
- Suppress HoverCard when hovering the delete button

* refactor: extract formatKeybinding and adjacentHint into testable modules

- Extract formatKeybinding into format-keybinding.ts (pure function,
  no vscode dependency, takes mac boolean parameter)
- Extract adjacentHint into navigate.ts as a reusable pure function
  for computing directional keybind hints
- Add tests for adjacentHint (12 cases) and formatKeybinding (13 cases)
- Simplify tab/worktree direction logic in AgentManagerApp to use
  adjacentHint instead of inline index arithmetic
2026-02-20 12:26:04 +00:00
kilo-maintainer[bot] 658878a362 chore: update nix node_modules hashes 2026-02-20 12:23:45 +00:00
Marian Alexandru Alecu cb13f4e715 Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-20 14:20:56 +02:00
Alex Alecu e2c2de2447 feat(plan): display plan message as non-synthetic in new sessions 2026-02-20 14:19:18 +02:00
Marius b54840ace0 fix(agent-manager): left-align add-session button next to tabs (#519)
The + button was pushed to the far right alongside the terminal button
because the tab scroll area used flex:1 to fill all available space.
Replace flex:1 with flex-shrink:1 so the scroll area only sizes to its
content, keeping the + button immediately after the last tab.
2026-02-20 13:17:00 +01:00
Marius 70f94c4054 feat: drag-and-drop tab reordering in agent manager (#517)
* tmp

* feat: drag-and-drop tab reordering in agent-manager

Extract tab ordering logic into tab-order.ts with reconcileOrder,
applyTabOrder, firstOrderedTitle. Extract SortableTab and
ConstrainDragYAxis into sortable-tab.tsx. Persist tab order via
WorktreeStateManager to .kilocode/agent-manager.json. Add unit tests.

* cleanup: remove duplicate tests, unused code, and stale re-export

- Delete reorder-tabs.test.ts (merged into tab-order.test.ts)
- Remove reconcileOrder (duplicate of applyTabOrder)
- Remove unused session variable in removeSession
- Remove stale reorderTabs re-export from navigate.ts

* fix: use applyTabOrder for local tab recovery, remove unused pending prop

- Local tab order recovery now uses applyTabOrder (consistent with worktree
  handling), gracefully appending new sessions instead of dropping the order
- Remove unused pending prop from SortableTab component
2026-02-20 13:15:45 +01:00
Marius 4e0c912612 feat(agent-manager): add worktree setup script support (#492)
* feat(agent-manager): add worktree setup script support

Add SetupScriptService and SetupScriptRunner to manage and execute
worktree setup scripts stored at .kilocode/setup-script. Scripts run
in a VS Code terminal during worktree creation, blocking session start
until complete. Adds settings gear menu in WORKTREES section header
and overlay progress step.

* refactor(agent-manager): use kilo-ui DropdownMenu, extract setup script logic

- Replace custom dropdown with kilo-ui DropdownMenu component
- Extract buildSetupCommand into standalone testable module
- Move default template to setup-script-template.sh
- Remove chmod (unnecessary since runner uses sh explicitly)
- Remove custom am-options-* CSS (handled by kilo-ui)
- Add unit tests for buildSetupCommand (Unix + Windows)

* fix: address PR review comments

- Inline template as TS string constant (fixes ENOENT in packaged VSIX)
- Log error in catch block instead of swallowing silently
- Escape shell-special chars (", $, `, \) in Unix paths
- Add onDidCloseTerminal fallback to runViaShellIntegration
- Fix misleading 'non-blocking' comments (setup script blocks session start)
- Add tests for shell escaping (quotes, dollar signs, backticks)

* fix: remove stray non-blocking label from error log

* fix: use mock.module in git-context tests to avoid cross-file mock leakage
2026-02-20 13:13:53 +01:00
Igor Šćekić 9193972c3b test(vscode): add message contract consistency tests (static analysis) 2026-02-20 13:13:15 +01:00
Marius 992a1bbbf1 feat(vscode): add resizable sidebar to agent manager (#509)
* feat(vscode): add resizable sidebar to agent manager

Add drag-to-resize support for the agent manager left sidebar using
the existing ResizeHandle component. Width defaults to 260px, can be
resized between 200px and 40% of the viewport, and persists across
webview state recoveries.

* fix(vscode): read window.innerWidth at drag time for accurate max sidebar width

Evaluate the viewport-based max constraint inside the onResize callback
so it reflects the current panel size, not the size at initial render.
2026-02-20 09:12:57 -03:00
Igor Šćekić 5eac807d10 test(vscode): extract telemetry payload building and auth header tests 2026-02-20 13:11:03 +01:00
Igor Šćekić 568d21a816 test(vscode): extract CSP string building and add policy directive tests 2026-02-20 13:09:52 +01:00
Igor Šćekić cd36bfa973 test(vscode): extract image MIME filtering and drag-leave detection tests 2026-02-20 13:08:49 +01:00
Igor Šćekić 1257c675b1 test(vscode): extract file mention pattern matching and attachment building tests 2026-02-20 13:07:14 +01:00
Igor Šćekić 36c223b55c test(vscode): extract locale normalization and template interpolation tests 2026-02-20 13:05:27 +01:00
Igor Šćekić 464c3e1541 test(vscode): extract provider model flattening and lookup with tests 2026-02-20 13:03:20 +01:00
Igor Šćekić 277f45e249 test(vscode): extract session status/cost/context-usage utils and add tests 2026-02-20 13:02:20 +01:00
Igor Šćekić db96bd833c test(vscode): extract git diff URI parsing and add scheme/ref tests 2026-02-20 13:00:22 +01:00
Igor Šćekić 51430b228c test(vscode): extract autocomplete telemetry key and LRU eviction tests 2026-02-20 12:59:12 +01:00
Igor Šćekić be398e935c test(vscode): extract status bar formatting helpers and add cost/time tests 2026-02-20 12:57:50 +01:00
Igor Šćekić 2f56af1cf5 test(vscode): extract chat autocomplete finalization and prefix-building tests 2026-02-20 12:56:17 +01:00
Igor Šćekić 88ab67600d test(vscode): extract parseAutocompleteResponse and add COMPLETION tag tests 2026-02-20 12:55:08 +01:00
Igor Šćekić e96d83ac7a test(vscode): extract autocomplete inline pure functions and add tests 2026-02-20 12:53:55 +01:00
Igor Šćekić 6bf7d99d5a test(vscode): extract SSE payload unwrapper and add parsing tests 2026-02-20 12:50:21 +01:00
Alex Alecu d4231c20e3 fix: Close sub-agents, preventing them from becoming orphan processes 2026-02-20 13:49:51 +02:00
Igor Šćekić d9f7d602ee test(vscode): extract CLI port parsing and add regex contract tests 2026-02-20 12:49:17 +01:00
Igor Šćekić 268f6b5306 test(vscode): extract HTTP error parsing and SSE line parser with tests 2026-02-20 12:48:26 +01:00
Igor Šćekić f9fce33c11 test(vscode): extract resolveEventSessionId and add SSE routing tests 2026-02-20 12:47:18 +01:00
Marian Alexandru Alecu 586bc2c730 Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-20 13:46:43 +02:00
Igor Šćekić dda9d3498e test(vscode): extract KiloProvider pure transforms and add unit tests 2026-02-20 12:46:21 +01:00
Igor Šćekić 81601ff715 test(vscode): add autocomplete i18n shim interpolation tests 2026-02-20 12:43:50 +01:00
Igor Šćekić a11efbc1a9 test(vscode): add contextual skip and language terminator tests 2026-02-20 12:43:20 +01:00
Igor Šćekić 442c843264 test(vscode): add autocomplete duplicate/repetition filter tests 2026-02-20 12:42:46 +01:00
Igor Šćekić 7194b2c6fd test(vscode): add formatRelativeDate boundary tests 2026-02-20 12:42:16 +01:00
Igor Šćekić f94689522f test(vscode): add permission queue upsert and removal tests 2026-02-20 12:41:52 +01:00
Igor Šćekić 803dea9844 test(vscode): add telemetry error class and type guard tests 2026-02-20 12:40:59 +01:00
Igor Šćekić 27a6b81816 test(vscode): add support-prompt createPrompt tests 2026-02-20 12:40:13 +01:00
Igor Šćekić cf6997c109 chore: add kilocode_change markers to PR #479 changes in packages/ui 2026-02-20 12:19:06 +01:00
Remon Oldenbeuving 3b35b06ee2 Merge pull request #421 from Githubguy132010/fix/vscode-permission-prompt-408
fix(vscode): stop duplicate permission prompts (#408)
2026-02-20 12:11:33 +01:00
Igor Šćekić 8fb1ef12b8 Merge remote-tracking branch 'origin/dev' into fix/vscode-permission-prompt-408 2026-02-20 11:53:31 +01:00
Igor Šćekić 370e28f8a2 fix(vscode): gate permission dock by tool presence, revert session-prompt-dock 2026-02-20 11:50:25 +01:00
Marius f0d975d92b feat(vscode): add Cmd+Shift+M keybinding to open Agent Manager (#512) 2026-02-20 11:44:48 +01:00
Marius ecd764be58 docs: add worktree instruction to AGENTS.md (#508) 2026-02-20 11:44:38 +01:00
Marius 1a3ea9a3b1 fix(agent-manager): preserve tab selection when switching between worktrees (#514)
Previously, switching between worktrees or local in the sidebar always
reset to the first tab. This adds per-context tab memory that saves the
active tab before switching away and restores it when switching back.
2026-02-20 11:44:27 +01:00
Marius 8d6411a5fc fix(vscode): improve worktree error messages when not in a git repository (#513)
Clarify error messaging when users try to use worktrees without a git
repository open. The setup overlay now shows 'Workspace setup failed'
as the title on error, with actionable messages explaining what the
user needs to do. Also widen the setup card and center error text to
prevent layout issues with longer messages.
2026-02-20 11:42:05 +01:00
Marius ca97194bae feat(agent-manager): accept Cmd+Enter as confirm in delete worktree dialog (#515) 2026-02-20 11:41:47 +01:00
Marius 69f1ab3299 fix(vscode): hide scrollbar and add fade indicators for agent manager tab overflow (#510)
Replace the native horizontal scrollbar on the session tab bar with hidden
overflow and gradient fade indicators on left/right edges. Vertical wheel
events are converted to horizontal scroll, and the active tab auto-scrolls
into view on selection.
2026-02-20 11:41:35 +01:00
Alex Alecu d5bceac21e feat: Handover task list and compacted context to next session after planning 2026-02-20 12:28:21 +02:00
Marian Alexandru Alecu 104c34ff49 Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-20 08:39:44 +02:00
pandemicsyn 0743eb16b6 Add quick docs for KiloClaw's changelog 2026-02-19 21:11:43 -06:00
Catriel Müller 20d17b48f0 Merge branch 'dev' into fix-406 2026-02-19 15:08:15 -03:00
Marian Alexandru Alecu 72ce6fbb72 Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-19 16:59:33 +02:00
Olusammytee 42e70cbdef docs: clarify YAML-first custom modes behavior 2026-02-19 09:44:20 -05:00
Igor Šćekić 25f3eac9a6 feat(vscode): make filenames in chat clickable to open editor tab (#461, #404)
Add onOpenFile callback to shared DataProvider so tool renderers can
trigger file-open in the host environment. In the VS Code extension,
clicking a filename posts an openFile message to the extension host
which resolves the path and opens the document in a preview tab.

Tool call headers (read, edit, write, apply_patch) now show pointer
cursor and underline on hover for file paths. Inline code in markdown
prose that looks like a file path (relative or absolute, with optional
:line or :line:col suffix) is wrapped with a file-link class and opens
on click via delegated event handling. When a line number is present,
the editor scrolls to that line.

Also adds cursor:pointer to user-message attachments to fix the
general clickable-items discoverability issue.
2026-02-19 15:41:02 +01:00
Olusammytee db43f2bccd docs: update mode-specific custom instruction file guidance 2026-02-19 09:38:31 -05:00
Olusammytee 4fd19a1cd7 docs(cloud-agent): clarify Setup Commands vs .kilocode/setup-script 2026-02-19 09:32:03 -05:00
Catriel Müller 012b1a167a Merge branch 'dev' into fix-406 2026-02-19 11:05:22 -03:00
Catriel Müller 65432a1275 feat: update flake 2026-02-19 10:59:42 -03:00
Catriel Müller 3a82fee72a refactor: move changes to kilo-ui 2026-02-19 10:57:54 -03:00
Catriel Müller 0fd1a6f90f Merge branch 'dev' into catrielmuller/320-notifications-vscode 2026-02-19 09:57:34 -03:00
Marian Alexandru Alecu 3c03da9a5f Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-19 14:09:52 +02:00
Alex Alecu 9a9d675ada test: add withInstance helper, use answer constants 2026-02-19 13:20:04 +02:00
Alex Alecu b2ff4b088a refactor: split ask(), extract constants, remove redundant context label 2026-02-19 13:20:00 +02:00
Marian Alexandru Alecu d37105ae89 Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-19 13:12:12 +02:00
Mark IJbema 3bd21e9c3e Merge branch 'dev' into fix/vscode-permission-prompt-408 2026-02-19 12:02:07 +01:00
Igor Šćekić ca1a453107 Merge branch 'dev' into fix/vscode-permission-prompt-408 2026-02-19 11:50:53 +01:00
Marian Alexandru Alecu ee058154e8 Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-19 12:05:39 +02:00
Marian Alexandru Alecu b19c4fc416 Merge branch 'dev' into feat/suggestions-after-plan-end 2026-02-19 12:00:31 +02:00
Alex Alecu 294846f706 fix: Reject pending plan followup question on abort signal 2026-02-19 11:59:57 +02:00
Alex Alecu 52ef5c926f fix: Avoid empty context 2026-02-19 11:48:21 +02:00
Alex Alecu a5e6ceb76e feat: When starting a new session after planning, include a compact summary of what was explored and which files were read so the AI doesn't have to re-search the codebase. 2026-02-19 11:42:35 +02:00
Alex Alecu 2d46b17f6c feat: Add predefined suggestions after finishing the planning session to improve context management 2026-02-19 10:23:19 +02:00
Halil İbrahim ceylan 35dc27e805 fix(ui): show horizontal scrollbar on code blocks in markdown 2026-02-18 23:53:50 +00:00
Halil İbrahim ceylan e3b9da27df fix(ui): remove redundant copy button from TextPartDisplay 2026-02-18 23:11:15 +00:00
Thomas Brugman 62b2385eab Merge pull request #3 from Githubguy132010/codex/gate-permission-dock-rendering-by-tool-presence
Codex-generated pull request
2026-02-18 21:09:32 +01:00
Thomas Brugman ff769cee01 Fix permission dock fallback for non-tool requests 2026-02-18 21:08:30 +01:00
Thomas Brugman ead119e3c1 Merge branch 'dev' into fix/vscode-permission-prompt-408 2026-02-18 21:02:25 +01:00
ops 34d382fb52 fix: add length constraint in question tool prompt 2026-02-18 20:05:34 +01:00
Thomas Brugman 15ecbee4e9 Merge branch 'dev' into fix/vscode-permission-prompt-408 2026-02-18 18:49:35 +01:00
Catriel Müller 28d9ea3c31 Merge branch 'dev' into catrielmuller/320-notifications-vscode 2026-02-18 14:46:33 -03:00
Catriel Müller 1c98ba6f51 feat(vscode): add Kilo notifications banner to VS Code extension
Ports the CLI's Kilo news/notifications feature to the VS Code extension.
Shows a dismissable carousel banner at the top of the chat view when no session is active, fetching notifications from the kilo-gateway API with dismissed IDs persisted in extension globalState.
2026-02-18 14:29:39 -03:00
Thomas Brugman cba4b1065e fix(vscode): stop duplicate permission prompts (#408) 2026-02-18 13:01:25 +01:00
229 changed files with 10300 additions and 1380 deletions
+25
View File
@@ -0,0 +1,25 @@
name: Check Links
on:
push:
branches: [main, dev]
pull_request:
schedule:
# Run daily at 9am UTC
- cron: "0 9 * * *"
workflow_dispatch: # Allow manual trigger
jobs:
link-checker:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Link Checker
uses: lycheeverse/lychee-action@v2
with:
args: "**/*.md"
workingDirectory: packages/kilo-docs
fail: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+32
View File
@@ -0,0 +1,32 @@
name: test-vscode
on:
push:
branches:
- dev
paths:
- "packages/kilo-vscode/**"
pull_request:
paths:
- "packages/kilo-vscode/**"
workflow_dispatch:
jobs:
unit:
name: unit tests
runs-on: blacksmith-4vcpu-ubuntu-2404
defaults:
run:
shell: bash
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Bun
uses: ./.github/actions/setup-bun
- name: Run unit tests
working-directory: packages/kilo-vscode
run: bun run test:unit
+1
View File
@@ -6,6 +6,7 @@ Kilo CLI is an open source AI coding agent that generates code from natural lang
- The default branch in this repo is `dev`.
- Local `main` ref may not exist; use `dev` or `origin/dev` for diffs.
- Prefer automation: execute requested actions without confirmation unless blocked by missing info or safety/irreversibility.
- You may be running in a git worktree. All changes must be made in your current working directory — never modify files in the main repo checkout.
## Build and Dev
+1 -1
View File
@@ -1,6 +1,6 @@
# Contributing to Kilo CLI
See [the Documentation for details on contributing](https://kilo.ai/docs/extending/contributing-to-kilo).
See [the Documentation for details on contributing](https://kilo.ai/docs/contributing).
## TL;DR
+1 -88
View File
@@ -1,88 +1 @@
<p align="center">
<a href="https://marketplace.visualstudio.com/items?itemName=kilocode.Kilo-Code"><img src="https://img.shields.io/badge/VS_Code_Marketplace-007ACC?style=flat&logo=visualstudiocode&logoColor=white" alt="VS Code Marketplace"></a>
<a href="https://x.com/kilocode"><img src="https://img.shields.io/badge/kilocode-000000?style=flat&logo=x&logoColor=white" alt="X (Twitter)"></a>
<a href="https://blog.kilo.ai"><img src="https://img.shields.io/badge/Blog-555?style=flat&logo=substack&logoColor=white" alt="Substack Blog"></a>
<a href="https://kilo.ai/discord"><img src="https://img.shields.io/badge/Join%20Discord-5865F2?style=flat&logo=discord&logoColor=white" alt="Discord"></a>
<a href="https://www.reddit.com/r/kilocode/"><img src="https://img.shields.io/badge/Join%20r%2Fkilocode-D84315?style=flat&logo=reddit&logoColor=white" alt="Reddit"></a>
</p>
# 🚀 Kilo
> Kilo is the all-in-one agentic engineering platform. Build, ship, and iterate faster with the most popular open source coding agent.
> #1 on OpenRouter. 1.5M+ Kilo Coders. 25T+ tokens processed
- ✨ Generate code from natural language
- ✅ Checks its own work
- 🧪 Run terminal commands
- 🌐 Automate the browser
- ⚡ Inline autocomplete suggestions
- 🤖 Latest AI models
- 🎁 API keys optional
- 💡 **Get $20 in bonus credits when you top-up for the first time** Credits can be used with 500+ models like Gemini 3 Pro, Claude 4.5 Sonnet & Opus, and GPT-5
<p align="center">
<img src="https://media.githubusercontent.com/media/Kilo-Org/kilocode/main/kilo.gif" width="100%" />
</p>
## Quick Links
- [VS Code Marketplace](https://kilo.ai/vscode-marketplace?utm_source=Readme) (download)
- Install CLI: `npm install -g @kilocode/cli`
- [Official Kilo.ai Home page](https://kilo.ai) (learn more)
## Key Features
- **Code Generation:** Kilo can generate code using natural language.
- **Inline Autocomplete:** Get intelligent code completions as you type, powered by AI.
- **Task Automation:** Kilo can automate repetitive coding tasks to save time.
- **Automated Refactoring:** Kilo can refactor and improve existing code efficiently.
- **MCP Server Marketplace**: Kilo can easily find, and use MCP servers to extend the agent capabilities.
- **Multi Mode**: Plan with Architect, Code with Coder, and Debug with Debugger, and make your own custom modes.
## Get Started in Visual Studio Code
1. Install the Kilo Code extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=kilocode.Kilo-Code).
2. Create your account to access 500+ cutting-edge AI models including Gemini 3 Pro, Claude 4.5 Sonnet & Opus, and GPT-5 with transparent pricing that matches provider rates exactly.
3. Start coding with AI that adapts to your workflow. Watch our quick-start guide to see Kilo in action:
[![Watch the video](https://img.youtube.com/vi/pqGfYXgrhig/maxresdefault.jpg)](https://youtu.be/pqGfYXgrhig)
## Get Started with the CLI
```bash
# npm
npm install -g @kilocode/cli
# Or run directly with npx
npx @kilocode/cli
```
Then run `kilo` in any project directory to start.
### Autonomous Mode (CI/CD)
Use the `--auto` flag with `kilo run` to enable fully autonomous operation without user interaction. This is ideal for CI/CD pipelines and automated workflows:
```bash
kilo run --auto "run tests and fix any failures"
```
**Important:** The `--auto` flag disables all permission prompts and allows the agent to execute any action without confirmation. Only use this in trusted environments like CI/CD pipelines.
## Contributing
We welcome contributions from developers, writers, and enthusiasts!
To get started, please read our [Contributing Guide](/CONTRIBUTING.md). It includes details on setting up your environment, coding standards, types of contribution and how to submit pull requests.
## Code of Conduct
Our community is built on respect, inclusivity, and collaboration. Please review our [Code of Conduct](/CODE_OF_CONDUCT.md) to understand the expectations for all contributors and community members.
## License
This project is licensed under the MIT License.
Youre free to use, modify, and distribute this code, including for commercial purposes as long as you include proper attribution and license notices. See [License](/LICENSE).
### Where did Kilo CLI come from?
Kilo CLI is a fork of [OpenCode](https://github.com/anomalyco/opencode), enhanced to work within the Kilo agentic engineering platform.
This repo has been moved to https://github.com/Kilo-Org/kilocode
+15 -14
View File
@@ -23,7 +23,7 @@
},
"packages/app": {
"name": "@opencode-ai/app",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"@kilocode/kilo-i18n": "workspace:*",
"@kilocode/kilo-ui": "workspace:*",
@@ -75,7 +75,7 @@
},
"packages/desktop": {
"name": "@opencode-ai/desktop",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"@opencode-ai/app": "workspace:*",
"@opencode-ai/ui": "workspace:*",
@@ -108,7 +108,7 @@
},
"packages/kilo-docs": {
"name": "@kilocode/kilo-docs",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"@docsearch/css": "^4",
"@docsearch/js": "^4",
@@ -136,7 +136,7 @@
},
"packages/kilo-gateway": {
"name": "@kilocode/kilo-gateway",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"@clack/prompts": "1.0.0-alpha.1",
"@kilocode/plugin": "workspace:*",
@@ -168,7 +168,7 @@
},
"packages/kilo-i18n": {
"name": "@kilocode/kilo-i18n",
"version": "1.0.24",
"version": "1.0.25",
"devDependencies": {
"@tsconfig/node22": "catalog:",
"@types/bun": "catalog:",
@@ -178,7 +178,7 @@
},
"packages/kilo-telemetry": {
"name": "@kilocode/kilo-telemetry",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"@kilocode/kilo-gateway": "workspace:*",
"@opentelemetry/api": "1.9.0",
@@ -198,7 +198,7 @@
},
"packages/kilo-ui": {
"name": "@kilocode/kilo-ui",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"@kobalte/core": "0.13.11",
},
@@ -221,13 +221,14 @@
},
"packages/kilo-vscode": {
"name": "kilo-code",
"version": "7.0.24",
"version": "7.0.25",
"dependencies": {
"@anthropic-ai/sdk": "^0.39.0",
"@kilocode/kilo-i18n": "workspace:*",
"@kilocode/kilo-ui": "workspace:*",
"@kilocode/sdk": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"@thisbeyond/solid-dnd": "0.7.5",
"diff": "^7.0.0",
"dotenv": "^16.4.7",
"eventsource": "^2.0.2",
@@ -264,7 +265,7 @@
},
"packages/opencode": {
"name": "@kilocode/cli",
"version": "1.0.24",
"version": "1.0.25",
"bin": {
"kilo": "./bin/kilo",
"kilocode": "./bin/kilocode",
@@ -374,7 +375,7 @@
},
"packages/plugin": {
"name": "@kilocode/plugin",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"@kilocode/sdk": "workspace:*",
"zod": "catalog:",
@@ -388,14 +389,14 @@
},
"packages/script": {
"name": "@opencode-ai/script",
"version": "1.0.24",
"version": "1.0.25",
"devDependencies": {
"@types/bun": "catalog:",
},
},
"packages/sdk/js": {
"name": "@kilocode/sdk",
"version": "1.0.24",
"version": "1.0.25",
"devDependencies": {
"@hey-api/openapi-ts": "0.90.10",
"@tsconfig/node22": "catalog:",
@@ -406,7 +407,7 @@
},
"packages/ui": {
"name": "@opencode-ai/ui",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"@kilocode/sdk": "workspace:*",
"@kobalte/core": "catalog:",
@@ -448,7 +449,7 @@
},
"packages/util": {
"name": "@opencode-ai/util",
"version": "1.0.24",
"version": "1.0.25",
"dependencies": {
"zod": "catalog:",
},
Generated
+3 -3
View File
@@ -2,11 +2,11 @@
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1770073757,
"narHash": "sha256-Vy+G+F+3E/Tl+GMNgiHl9Pah2DgShmIUBJXmbiQPHbI=",
"lastModified": 1771207753,
"narHash": "sha256-b9uG8yN50DRQ6A7JdZBfzq718ryYrlmGgqkRm9OOwCE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "47472570b1e607482890801aeaf29bfb749884f6",
"rev": "d1c15b7d5806069da59e819999d70e1cec0760bf",
"type": "github"
},
"original": {
+1
View File
@@ -162,6 +162,7 @@
unzip
gnutar
gzip
ripgrep
kilo-dev
kilo-install-bin
kilo-bin
+4 -4
View File
@@ -1,8 +1,8 @@
{
"nodeModules": {
"x86_64-linux": "sha256-LVuT8+lBSeogRYQQHruUJJBeSRw9jd3arXy1GLzg9JM=",
"aarch64-linux": "sha256-QDTbTB4Lcc9u5MdEdZZ07GBBbLQkcl2NrwvxRc5WMsk=",
"aarch64-darwin": "sha256-skuEhDRrT585MJL58SpPOqnz0ivrlzShCRkA2f/YIxU=",
"x86_64-darwin": "sha256-Ocf8Mq9dgniaUlUAs0D/ygggh9ozVr8FydkgDsCsEPI="
"x86_64-linux": "sha256-V1SML9naH7HShbdovoQIUc46rH6YNgFF9MSTw95k0fU=",
"aarch64-linux": "sha256-wddgxfbK7v7O/zsdbx0e/TNYAw0KzzxyQbuUdwudf/Y=",
"aarch64-darwin": "sha256-y7bMXWMSiHTHfKKiJ+c/2WRJmc7mCw2o601Ny8W5Zzs=",
"x86_64-darwin": "sha256-hXdKlmVFWq2C0kJWgO1+g82B+/fvn9CG/JQyR31QtzY="
}
}
+1 -1
View File
@@ -102,6 +102,6 @@
"@standard-community/standard-openapi@0.2.9": "patches/@standard-community%2Fstandard-openapi@0.2.9.patch",
"ghostty-web@0.3.0": "patches/ghostty-web@0.3.0.patch"
},
"version": "1.0.24",
"version": "1.0.25",
"peerDependencies": {}
}
@@ -2,7 +2,9 @@ import { test, expect } from "../fixtures"
import { promptSelector } from "../selectors"
import { closeDialog, openSettings, clickListItem } from "../actions"
test("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
// kilocode_change start
test.skip("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
// kilocode_change end
await gotoSession()
await page.locator(promptSelector).click()
@@ -2,7 +2,9 @@ import { test, expect } from "../fixtures"
import { promptSelector } from "../selectors"
import { closeDialog, openSettings } from "../actions"
test("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
// kilocode_change start
test.skip("hiding a model removes it from the model picker", async ({ page, gotoSession }) => {
// kilocode_change end
await gotoSession()
await page.locator(promptSelector).click()
@@ -60,7 +62,9 @@ test("hiding a model removes it from the model picker", async ({ page, gotoSessi
await expect(pickerAgain).toHaveCount(0)
})
test("showing a hidden model restores it to the model picker", async ({ page, gotoSession }) => {
// kilocode_change start
test.skip("showing a hidden model restores it to the model picker", async ({ page, gotoSession }) => {
// kilocode_change end
await gotoSession()
await page.locator(promptSelector).click()
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@opencode-ai/app",
"version": "1.0.24",
"version": "1.0.25",
"description": "",
"type": "module",
"exports": {
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "@opencode-ai/desktop",
"private": true,
"version": "1.0.24",
"version": "1.0.25",
"type": "module",
"license": "MIT",
"scripts": {
+6 -6
View File
@@ -1,7 +1,7 @@
id = "kilo"
name = "Kilo"
description = "The open source coding agent."
version = "1.0.24"
version = "1.0.25"
schema_version = 1
authors = ["Anomaly"]
repository = "https://github.com/Kilo-Org/kilo"
@@ -11,26 +11,26 @@ name = "Kilo"
icon = "./icons/opencode.svg"
[agent_servers.opencode.targets.darwin-aarch64]
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-darwin-arm64.zip"
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-darwin-arm64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.darwin-x86_64]
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-darwin-x64.zip"
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-darwin-x64.zip"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-aarch64]
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-linux-arm64.tar.gz"
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-linux-arm64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.linux-x86_64]
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-linux-x64.tar.gz"
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-linux-x64.tar.gz"
cmd = "./opencode"
args = ["acp"]
[agent_servers.opencode.targets.windows-x86_64]
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.24/opencode-windows-x64.zip"
archive = "https://github.com/Kilo-Org/kilo/releases/download/v1.0.25/opencode-windows-x64.zip"
cmd = "./opencode.exe"
args = ["acp"]
+2 -1
View File
@@ -8,4 +8,5 @@ screenshots/
.beads/
.env
next-env.d.ts
tsconfig.tsbuildinfo
tsconfig.tsbuildinfo
lycheeout.*
-55
View File
@@ -1,55 +0,0 @@
# Full Next.js example
This is a full-featured boilerplate for a creating a documentation website using Markdoc and Next.js.
<img width="2032" alt="image" src="https://user-images.githubusercontent.com/62121649/174916143-16f18270-0463-402c-8b48-33c627ea7a7e.png">
## Setup
First, clone this repo and install the dependencies required:
```bash
npm install
# or
yarn install
```
Then, run the development server:
```bash
npm run dev
# or
yarn dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `index.md`. The page auto-updates as you edit the file.
## Deploy
The quickest way to deploy your own version of this boilerplate is by deploying it with [Vercel](https://vercel.com) or [Netlify](https://www.netlify.com/) by clicking one of the buttons below.
### Deploy with Vercel
[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/markdoc/next.js-starter)
### Deploy to Netlify
[![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/markdoc/next.js-starter)
## Contributing
When making documentation _only_ changes, use branch names prefixed with `docs/`:
```bash
git checkout -b docs/your-change-description
```
Examples:
- `docs/add-mcp-tutorial`
- `docs/fix-installation-steps`
- `docs/update-api-reference`
For full contribution guidelines, see the [Contributing Guide](https://kilo.ai/docs/contributing).
@@ -34,10 +34,6 @@ export const ContributingNav: NavSection[] = [
href: "/contributing/architecture/agent-observability",
children: "Agent Observability",
},
{
href: "/contributing/architecture/annual-billing",
children: "Annual Billing",
},
{
href: "/contributing/architecture/benchmarking",
children: "Benchmarking",
-1
View File
@@ -41,7 +41,6 @@ export const CustomizeNav: NavSection[] = [
href: "/customize/context/kilocodeignore",
children: ".kilocodeignore",
},
{ href: "/customize/context/memory-bank", children: "Memory Bank" },
{
href: "/customize/context/large-projects",
children: "Large Projects",
+28
View File
@@ -0,0 +1,28 @@
root_dir = "."
fallback_extensions = ["md"]
remap = ["kilo-docs/docs kilo-docs/pages"]
format = "detailed"
max_redirects = 2
exclude_path = ["node_modules"]
accept = [
"200",
"403",
"429",
"301",
"307",
]
exclude = [
'\.png$',
'https://synthetic.new/user-settings/api',
'https://platform.slack-edge.com/img/add_to_slack.png',
'https://console.groq.com/pages/models',
'https://glama.ai/settings/gateway/api-keys',
'^https?://(api|console)\.mistral\.ai',
'^https?://(app|console)\.requesty\.ai',
'^https?://(cloud|console)\.google\.ai',
'https://opencode.ai/pages/config',
'^localhost:3000/'
]
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@kilocode/kilo-docs",
"version": "1.0.24",
"version": "1.0.25",
"private": true,
"scripts": {
"dev": "next dev --webpack --port 3002",
+7 -2
View File
@@ -73,7 +73,7 @@ export default function MyApp({ Component, pageProps }: AppProps<MyAppProps>) {
posthog.capture("$pageview")
}, [])
// Close mobile menu on route change and track pageviews
// Close mobile menu on route change, track pageviews, and reset scroll position
useEffect(() => {
const handleRouteChange = () => {
setIsMobileMenuOpen(false)
@@ -81,6 +81,11 @@ export default function MyApp({ Component, pageProps }: AppProps<MyAppProps>) {
const handleRouteComplete = () => {
posthog.capture("$pageview")
// Reset scroll position of the main content container on navigation
const mainContent = document.querySelector(".main-content")
if (mainContent) {
mainContent.scrollTop = 0
}
}
router.events.on("routeChangeStart", handleRouteChange)
@@ -175,7 +180,7 @@ export default function MyApp({ Component, pageProps }: AppProps<MyAppProps>) {
<div className="article-content flex column mt-5">
<Component {...pageProps} />
</div>
<div className="right-sidebar">
<div className="right-sidebar" key={router.asPath}>
{markdoc && <CopyPageButton />}
<TableOfContents toc={toc} />
</div>
@@ -25,4 +25,4 @@ Kilo Code supports Google's Gemini family of models through the Google AI Gemini
## Tips and Notes
- **Pricing:** Gemini API usage is priced based on input and output tokens. Refer to the [Gemini pricing page](https://ai.google.dev/pricing) for detailed information.
- **Codebase Indexing:** The `gemini-embedding-001` model is specifically supported for [codebase indexing](/docs/features/codebase-indexing), providing high-quality embeddings for semantic code search.
- **Codebase Indexing:** The `gemini-embedding-001` model is specifically supported for [codebase indexing](/docs/customize/context/codebase-indexing), providing high-quality embeddings for semantic code search.
@@ -70,4 +70,4 @@ With the Kilo Code provider, if you sign up with Google you can also connect oth
- **Latest Models:** Automatic access to the most current frontier coding models
- **Support Available:** Contact [hi@kilo.ai](mailto:hi@kilo.ai) for questions about pricing or tokens
For detailed setup instructions, see [Setting up Kilo Code](/docs/getting-started/setting-up).
For detailed setup instructions, see [Setting up Kilo Code](/docs/getting-started/setup-authentication).
@@ -27,4 +27,3 @@ MiniMax is a global AI foundation model company focused on fast, cost-efficient
- **Performance:** MiniMax M2.1 emphasizes fast inference, strong coding ability, and exceptional tool-calling performance.
- **Context Window:** MiniMax models support ultra-long context windows suitable for large codebases and agent workflows.
- **Pricing:** Pricing varies by model, with input costs ranging from $0.20 to $0.30 per million tokens and output costs from $1.10 to $2.20 per million tokens. Refer to the MiniMax documentation for the most current pricing information.
- **MiniMax M2.1** is currently available for free exclusively for [Kilo for Slack](/docs/slack).
@@ -4,7 +4,7 @@ sidebar_label: VS Code Language Model API
# Using VS Code Language Model API With Kilo Code
Kilo Code includes _experimental_ support for the [VS Code Language Model API](https://code.visualstudio.com/api/language-extensions/language-model-access). This API allows extensions to provide access to language models directly within VS Code. This means you can potentially use models from:
Kilo Code includes _experimental_ support for the [VS Code Language Model API](https://code.visualstudio.com/docs/copilot/customization/language-models). This API allows extensions to provide access to language models directly within VS Code. This means you can potentially use models from:
- **GitHub Copilot:** If you have a Copilot subscription and the extension installed.
- **Other VS Code Extensions:** Any extension that implements the Language Model API.
@@ -194,4 +194,4 @@ For additional support:
- Visit the [ZenMux documentation](https://zenmux.ai/docs)
- Contact ZenMux support through their dashboard
- Check the [Kilo Code GitHub repository](https://github.com/kilocode/kilocode) for integration-specific issues
- Check the [Kilo Code GitHub repository](https://github.com/Kilo-Org/kilo) for integration-specific issues
+79
View File
@@ -1,6 +1,8 @@
import type { NextApiRequest, NextApiResponse } from "next"
import fs from "fs"
import path from "path"
import { Nav } from "../../lib/nav"
import type { NavLink, NavSection } from "../../lib/types"
/**
* Recursively finds all markdown files in a directory
@@ -37,6 +39,51 @@ function filePathToUrlPath(filePath: string, pagesDir: string): string {
return "/" + relativePath
}
function extractFrontmatterTitle(content: string): string | null {
const match = content.match(/^---\n[\s\S]*?^title:\s*"?([^"\n]+)"?\s*$[\s\S]*?^---\n/m)
if (!match) return null
return match[1]?.trim() || null
}
function buildTitleMap(markdownFiles: string[], pagesDir: string) {
const map = new Map<string, string>()
for (const filePath of markdownFiles) {
const urlPath = filePathToUrlPath(filePath, pagesDir)
const content = fs.readFileSync(filePath, "utf-8")
const title = extractFrontmatterTitle(content)
if (title) {
map.set(urlPath, title)
}
}
return map
}
function addNavLink(items: string[], link: NavLink, baseUrl: string, depth: number, titleMap: Map<string, string>) {
const indent = " ".repeat(depth)
const rawUrl = `${baseUrl}/api/raw-markdown?path=${encodeURIComponent(link.href)}`
const title = titleMap.get(link.href) || link.children
items.push(`${indent}- [${title}](${rawUrl})`)
if (link.subLinks) {
for (const subLink of link.subLinks) {
addNavLink(items, subLink, baseUrl, depth + 1, titleMap)
}
}
}
function addNavSection(items: string[], section: NavSection, baseUrl: string, titleMap: Map<string, string>) {
items.push(`### ${section.title}`)
items.push("")
for (const link of section.links) {
addNavLink(items, link, baseUrl, 0, titleMap)
}
items.push("")
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== "GET") {
return res.status(405).json({ error: "Method not allowed" })
@@ -58,6 +105,38 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
"This file contains the complete documentation for Kilo Code, the leading open source agentic engineering platform.",
)
sections.push("")
const protocol = req.headers["x-forwarded-proto"] || "https"
const host = req.headers.host || "kilo.ai"
const baseUrl = `${protocol}://${host}`
const titleMap = buildTitleMap(markdownFiles, pagesDir)
sections.push("## Page Index")
sections.push("")
sections.push("Each page is available as raw markdown via the /api/raw-markdown endpoint.")
sections.push("")
const navGroups = [
{ title: "Getting Started", nav: Nav.GettingStartedNav },
{ title: "Code with AI", nav: Nav.CodeWithAiNav },
{ title: "Customize", nav: Nav.CustomizeNav },
{ title: "Collaborate", nav: Nav.CollaborateNav },
{ title: "Automate", nav: Nav.AutomateNav },
{ title: "Deploy & Secure", nav: Nav.DeploySecureNav },
{ title: "Contributing", nav: Nav.ContributingNav },
{ title: "AI Providers", nav: Nav.AiProvidersNav },
{ title: "Gateway", nav: Nav.GatewayNav },
{ title: "Tools", nav: Nav.ToolsNav },
]
for (const group of navGroups) {
sections.push(`## ${group.title}`)
sections.push("")
for (const section of group.nav) {
addNavSection(sections, section, baseUrl, titleMap)
}
}
sections.push("---")
sections.push("")
@@ -16,7 +16,7 @@ This page reflects the actual implementation in the extension.
## Prerequisites
- Install/update the Kilo Code CLI (latest) — see [CLI setup](/docs/cli)
- Install/update the Kilo Code CLI (latest) — see [CLI setup](/docs/code-with-ai/platforms/cli)
- Open a project in VS Code (workspace required)
- Authentication: You must be logged in via the extension settings OR use CLI with kilocode as provider (see [Authentication Requirements](#authentication-requirements))
@@ -102,7 +102,7 @@ The Agent Manager requires proper authentication for full functionality, includi
2. **CLI with Kilo Code Provider**
- Use the CLI configured with `kilocode` as the provider
- Run `kilocode config` to set up authentication
- See [CLI setup](/docs/cli) for details
- See [CLI setup](/docs/code-with-ai/platforms/cli) for details
### BYOK Limitations
@@ -131,7 +131,7 @@ Message transcripts are fetched from a signed blob and exclude internal checkpoi
## Troubleshooting
- CLI not found or outdated
- Install/update the CLI: [CLI setup](/docs/cli)
- Install/update the CLI: [CLI setup](/docs/code-with-ai/platforms/cli)
- If you see an "unknown option --json-io" error, update to the latest CLI
- "Please open a folder…" error
- The Agent Manager requires a VS Code workspace folder
@@ -146,6 +146,6 @@ Message transcripts are fetched from a signed blob and exclude internal checkpoi
## Related features
- [Sessions](/docs/advanced-usage/sessions)
- [Auto-approving Actions](/docs/features/auto-approving-actions)
- [CLI](/docs/cli)
- [Sessions](/docs/collaborate/sessions-sharing)
- [Auto-approving Actions](/docs/getting-started/settings/auto-approving-actions)
- [CLI](/docs/code-with-ai/platforms/cli)
@@ -30,8 +30,8 @@ Kilo Code currently supports two main local model providers:
For detailed setup instructions, see:
- [Setting up Ollama](/docs/providers/ollama)
- [Setting up LM Studio](/docs/providers/lmstudio)
- [Setting up Ollama](/docs/ai-providers/ollama)
- [Setting up LM Studio](/docs/ai-providers/lmstudio)
Both providers offer similar capabilities but with different user interfaces and workflows. Ollama provides more control through its command-line interface, while LM Studio offers a more user-friendly graphical interface.
@@ -11,7 +11,7 @@ Terminal Shell Integration is a key feature that enables Kilo Code to execute co
Shell integration is automatically enabled in Kilo Code and connects directly to your terminal's command execution lifecycle without requiring any setup from you. This built-in feature allows Kilo Code to:
- Execute commands on your behalf through the [`execute_command`](/docs/features/tools/execute-command) tool
- Execute commands on your behalf through the [`execute_command`](/docs/automate/tools/execute-command) tool
- Read command output in real-time without manual copy-pasting
- Automatically detect and fix errors in running applications
- Observe command exit codes to determine success or failure
@@ -86,4 +86,4 @@ This safety mechanism ensures you maintain control over which files are modified
## Learn More About Tools
For more detailed information about each tool, including complete parameter references and advanced usage patterns, see the [Tool Use Overview](/docs/features/tools/tool-use-overview) documentation.
For more detailed information about each tool, including complete parameter references and advanced usage patterns, see the [Tool Use Overview](/docs/automate/tools) documentation.
@@ -58,6 +58,22 @@ Once created, you can control your instance from the dashboard.
| **Settings** | Model configuration and instance parameters |
| **Actions** | Quick actions and connected platform management |
### Changelog
Your instance page includes a changelog with recent KiloClaw platform updates.
Each changelog entry is labeled by update type:
- **Feature** — New capability or enhancement
- **Bug** — Fix for incorrect or broken behavior
Some entries also include a redeploy label:
- **Redeploy required** — You must redeploy your instance to fully take advantage of the change
- **Redeploy suggested** — Redeploy is optional and only needed if you want to use the new behavior
For example, if you manually configured a channel such as Telegram, and would prefer to have KiloClaw manage the channel for you, you would need to redeploy.
## Accessing Your Agent
To connect to your agent's web interface:
@@ -170,7 +170,7 @@ To set the maximum time to wait for a response after a tool call to the MCP serv
MCP tool auto-approval works on a per-tool basis and is disabled by default. To configure auto-approval:
1. First enable the global "Use MCP servers" auto-approval option in [auto-approving-actions](/docs/features/auto-approving-actions)
1. First enable the global "Use MCP servers" auto-approval option in [auto-approving-actions](/docs/getting-started/settings/auto-approving-actions)
2. Navigate to Settings > Agent Behaviour > MCP Servers, then locate the specific tool you want to auto-approve
3. Check the `Always allow` checkbox next to the tool name
@@ -1,7 +1,7 @@
# codebase_search
{% callout type="info" title="Setup Required" %}
The `codebase_search` tool is part of the [Codebase Indexing](/docs/features/codebase-indexing) feature. It requires additional setup including an embedding provider and vector database.
The `codebase_search` tool is part of the [Codebase Indexing](/docs/customize/context/codebase-indexing) feature. It requires additional setup including an embedding provider and vector database.
{% /callout %}
The `codebase_search` tool performs semantic searches across your entire codebase using AI embeddings. Unlike traditional text-based search, it understands the meaning of your queries and finds relevant code even when exact keywords don't match.
@@ -15,22 +15,22 @@ Tools are organized into logical groups based on their functionality:
| Category | Purpose | Tools | Common Use |
| ------------------ | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- |
| **Read Group** | File system reading and searching | [read_file](/docs/features/tools/read-file), [search_files](/docs/features/tools/search-files), [list_files](/docs/features/tools/list-files), [list_code_definition_names](/docs/features/tools/list-code-definition-names) | Code exploration and analysis |
| **Edit Group** | File system modifications | [apply_diff](/docs/features/tools/apply-diff), [delete_file](/docs/features/tools/delete-file), [write_to_file](/docs/features/tools/write-to-file) | Code changes and file manipulation |
| **Browser Group** | Web automation | [browser_action](/docs/features/tools/browser-action) | Web testing and interaction |
| **Command Group** | System command execution | [execute_command](/docs/features/tools/execute-command) | Running scripts, building projects |
| **MCP Group** | External tool integration | [use_mcp_tool](/docs/features/tools/use-mcp-tool), [access_mcp_resource](/docs/features/tools/access-mcp-resource) | Specialized functionality through external servers |
| **Workflow Group** | Mode and task management | [switch_mode](/docs/features/tools/switch-mode), [new_task](/docs/features/tools/new-task), [ask_followup_question](/docs/features/tools/ask-followup-question), [attempt_completion](/docs/features/tools/attempt-completion), [update_todo_list](/docs/features/tools/update-todo-list) | Context switching and task organization |
| **Read Group** | File system reading and searching | [read_file](/docs/automate/tools/read-file), [search_files](/docs/automate/tools/search-files), [list_files](/docs/automate/tools/list-files), [list_code_definition_names](/docs/automate/tools/list-code-definition-names) | Code exploration and analysis |
| **Edit Group** | File system modifications | [apply_diff](/docs/automate/tools/apply-diff), [delete_file](/docs/automate/tools/delete-file), [write_to_file](/docs/automate/tools/write-to-file) | Code changes and file manipulation |
| **Browser Group** | Web automation | [browser_action](/docs/automate/tools/browser-action) | Web testing and interaction |
| **Command Group** | System command execution | [execute_command](/docs/automate/tools/execute-command) | Running scripts, building projects |
| **MCP Group** | External tool integration | [use_mcp_tool](/docs/automate/tools/use-mcp-tool), [access_mcp_resource](/docs/automate/tools/access-mcp-resource) | Specialized functionality through external servers |
| **Workflow Group** | Mode and task management | [switch_mode](/docs/automate/tools/switch-mode), [new_task](/docs/automate/tools/new-task), [ask_followup_question](/docs/automate/tools/ask-followup-question), [attempt_completion](/docs/automate/tools/attempt-completion), [update_todo_list](/docs/automate/tools/update-todo-list) | Context switching and task organization |
### Always Available Tools
Certain tools are accessible regardless of the current mode:
- [ask_followup_question](/docs/features/tools/ask-followup-question): Gather additional information from users
- [attempt_completion](/docs/features/tools/attempt-completion): Signal task completion
- [switch_mode](/docs/features/tools/switch-mode): Change operational modes
- [new_task](/docs/features/tools/new-task): Create subtasks
- [update_todo_list](/docs/features/tools/update-todo-list): Manage step-by-step task tracking
- [ask_followup_question](/docs/automate/tools/ask-followup-question): Gather additional information from users
- [attempt_completion](/docs/automate/tools/attempt-completion): Signal task completion
- [switch_mode](/docs/automate/tools/switch-mode): Change operational modes
- [new_task](/docs/automate/tools/new-task): Create subtasks
- [update_todo_list](/docs/automate/tools/update-todo-list): Manage step-by-step task tracking
## Available Tools
@@ -38,47 +38,47 @@ Certain tools are accessible regardless of the current mode:
These tools help Kilo Code understand your code and project:
- [read_file](/docs/features/tools/read-file) - Examines the contents of files
- [search_files](/docs/features/tools/search-files) - Finds patterns across multiple files
- [list_files](/docs/features/tools/list-files) - Maps your project's file structure
- [list_code_definition_names](/docs/features/tools/list-code-definition-names) - Creates a structural map of your code
- [read_file](/docs/automate/tools/read-file) - Examines the contents of files
- [search_files](/docs/automate/tools/search-files) - Finds patterns across multiple files
- [list_files](/docs/automate/tools/list-files) - Maps your project's file structure
- [list_code_definition_names](/docs/automate/tools/list-code-definition-names) - Creates a structural map of your code
### Edit Tools
These tools help Kilo Code make changes to your code:
- [apply_diff](/docs/features/tools/apply-diff) - Makes precise, surgical changes to your code
- [delete_file](/docs/features/tools/delete-file) - Removes files from your workspace
- [write_to_file](/docs/features/tools/write-to-file) - Creates new files or completely rewrites existing ones
- [apply_diff](/docs/automate/tools/apply-diff) - Makes precise, surgical changes to your code
- [delete_file](/docs/automate/tools/delete-file) - Removes files from your workspace
- [write_to_file](/docs/automate/tools/write-to-file) - Creates new files or completely rewrites existing ones
### Browser Tools
These tools help Kilo Code interact with web applications:
- [browser_action](/docs/features/tools/browser-action) - Automates browser interactions
- [browser_action](/docs/automate/tools/browser-action) - Automates browser interactions
### Command Tools
These tools help Kilo Code execute commands:
- [execute_command](/docs/features/tools/execute-command) - Runs system commands and programs
- [execute_command](/docs/automate/tools/execute-command) - Runs system commands and programs
### MCP Tools
These tools help Kilo Code connect with external services:
- [use_mcp_tool](/docs/features/tools/use-mcp-tool) - Uses specialized external tools
- [access_mcp_resource](/docs/features/tools/access-mcp-resource) - Accesses external data sources
- [use_mcp_tool](/docs/automate/tools/use-mcp-tool) - Uses specialized external tools
- [access_mcp_resource](/docs/automate/tools/access-mcp-resource) - Accesses external data sources
### Workflow Tools
These tools help manage the conversation and task flow:
- [ask_followup_question](/docs/features/tools/ask-followup-question) - Gets additional information from you
- [attempt_completion](/docs/features/tools/attempt-completion) - Presents final results
- [switch_mode](/docs/features/tools/switch-mode) - Changes to a different mode for specialized tasks
- [new_task](/docs/features/tools/new-task) - Creates a new subtask
- [update_todo_list](/docs/features/tools/update-todo-list) - Tracks task progress with step-by-step checklists
- [ask_followup_question](/docs/automate/tools/ask-followup-question) - Gets additional information from you
- [attempt_completion](/docs/automate/tools/attempt-completion) - Presents final results
- [switch_mode](/docs/automate/tools/switch-mode) - Changes to a different mode for specialized tasks
- [new_task](/docs/automate/tools/new-task) - Creates a new subtask
- [update_todo_list](/docs/automate/tools/update-todo-list) - Tracks task progress with step-by-step checklists
## Tool Calling Mechanism
@@ -211,24 +211,24 @@ Tools are made available based on the current mode:
1. **Information Gathering**
```
[ask_followup_question](/docs/features/tools/ask-followup-question) → [read_file](/docs/features/tools/read-file) → [search_files](/docs/features/tools/search-files)
[ask_followup_question](/docs/automate/tools/ask-followup-question) → [read_file](/docs/automate/tools/read-file) → [search_files](/docs/automate/tools/search-files)
```
2. **Code Modification**
```
[read_file](/docs/features/tools/read-file) → [apply_diff](/docs/features/tools/apply-diff) → [attempt_completion](/docs/features/tools/attempt-completion)
[read_file](/docs/automate/tools/read-file) → [apply_diff](/docs/automate/tools/apply-diff) → [attempt_completion](/docs/automate/tools/attempt-completion)
```
3. **Task Management**
```
[new_task](/docs/features/tools/new-task) → [switch_mode](/docs/features/tools/switch-mode) → [execute_command](/docs/features/tools/execute-command)
[new_task](/docs/automate/tools/new-task) → [switch_mode](/docs/automate/tools/switch-mode) → [execute_command](/docs/automate/tools/execute-command)
```
4. **Progress Tracking**
```
[update_todo_list](/docs/features/tools/update-todo-list) → [execute_command](/docs/features/tools/execute-command) → [update_todo_list](/docs/features/tools/update-todo-list)
[update_todo_list](/docs/automate/tools/update-todo-list) → [execute_command](/docs/automate/tools/execute-command) → [update_todo_list](/docs/automate/tools/update-todo-list)
```
## Error Handling and Recovery
@@ -10,7 +10,7 @@ description: "Learn how to use the Kilo Code chat interface effectively"
{% /callout %}
{% callout type="note" title="Prefer quick completions?" %}
If you're typing code in the editor and want AI to finish your line or block, check out [Autocomplete](/docs/basic-usage/autocomplete) instead. Chat is best for larger tasks, explanations, and multi-file changes.
If you're typing code in the editor and want AI to finish your line or block, check out [Autocomplete](/docs/code-with-ai/features/autocomplete) instead. Chat is best for larger tasks, explanations, and multi-file changes.
{% /callout %}
## Quick Setup
@@ -41,7 +41,7 @@ Find the Kilo Code icon ({% kilo-code-icon /%}) in VS Code's Primary Side Bar. C
{% callout type="info" title="Chat vs Autocomplete" %}
**Use chat** when you need to describe what you want, ask questions, or make changes across multiple files.
**Use [autocomplete](/docs/basic-usage/autocomplete)** when you're already typing code and want the AI to finish your thought inline.
**Use [autocomplete](/docs/code-with-ai/features/autocomplete)** when you're already typing code and want the AI to finish your thought inline.
{% /callout %}
## The Chat Interface
@@ -73,19 +73,19 @@ Find the Kilo Code icon ({% kilo-code-icon /%}) in VS Code's Primary Side Bar. C
## Common Mistakes to Avoid
| Instead of this... | Try this |
| --------------------------------- | ------------------------------------------------------------------------- |
| "Fix the code" | "Fix the bug in `calculateTotal` that returns incorrect results" |
| Assuming Kilo knows context | Use `@` to reference specific files |
| Multiple unrelated tasks | Submit one focused request at a time |
| Technical jargon overload | Clear, straightforward language works best |
| Using chat for tiny code changes. | Use [autocomplete](/docs/basic-usage/autocomplete) for inline completions |
| Instead of this... | Try this |
| --------------------------------- | ----------------------------------------------------------------------------------- |
| "Fix the code" | "Fix the bug in `calculateTotal` that returns incorrect results" |
| Assuming Kilo knows context | Use `@` to reference specific files |
| Multiple unrelated tasks | Submit one focused request at a time |
| Technical jargon overload | Clear, straightforward language works best |
| Using chat for tiny code changes. | Use [autocomplete](/docs/code-with-ai/features/autocomplete) for inline completions |
**Why it matters:** Kilo Code works best when you communicate like you're talking to a smart teammate who needs clear direction.
## Suggested Responses
When Kilo Code needs more information to complete a task, it uses the [`ask_followup_question`](/docs/features/tools/ask-followup-question) tool. To make responding easier and faster, Kilo Code often provides suggested answers alongside the question.
When Kilo Code needs more information to complete a task, it uses the [`ask_followup_question`](/docs/automate/tools/ask-followup-question) tool. To make responding easier and faster, Kilo Code often provides suggested answers alongside the question.
{% image src="/docs/img/suggested-responses/suggested-responses.png" alt="Example of Kilo Code asking a question with suggested response buttons below it" width="800" caption="Suggested responses appear as clickable buttons below questions" /%}
@@ -111,7 +111,7 @@ When you need more capability than free models provide, these options deliver ex
**Strategic file mentions:**
- Only include files directly relevant to the task
- Use [`@folder/`](/docs/basic-usage/context-mentions) for broad context, specific files for targeted work
- Use [`@folder/`](/docs/code-with-ai/agents/context-mentions) for broad context, specific files for targeted work
### Model Switching Strategies
@@ -233,7 +233,7 @@ When you need more capability than free models provide, these options deliver ex
**Optimize conversation length:**
- Use [Checkpoints](/docs/features/checkpoints) to reset context
- Use [Checkpoints](/docs/code-with-ai/features/checkpoints) to reset context
- Start fresh conversations for unrelated tasks
- Archive completed work
@@ -257,19 +257,19 @@ When you need more capability than free models provide, these options deliver ex
**Free tier foundation:**
- [OpenRouter](/docs/providers/openrouter) - Free models
- [Groq](/docs/providers/groq) - Fast inference for supported models
- [OpenRouter](/docs/ai-providers/openrouter) - Free models
- [Groq](/docs/ai-providers/groq) - Fast inference for supported models
- [Z.ai](https://z.ai/model-api) - Provides a free model GLM-4.5-Flash
**Budget tier options:**
- [DeepSeek](/docs/providers/deepseek) - Excellent value models
- [Mistral](/docs/providers/mistral) - Specialized coding models
- [DeepSeek](/docs/ai-providers/deepseek) - Excellent value models
- [Mistral](/docs/ai-providers/mistral) - Specialized coding models
**Premium tier backup:**
- [Anthropic](/docs/providers/anthropic) - Claude for complex reasoning
- [OpenAI](/docs/providers/openai) - GPT-4 for critical tasks
- [Anthropic](/docs/ai-providers/anthropic) - Claude for complex reasoning
- [OpenAI](/docs/ai-providers/openai) - GPT-4 for critical tasks
## Measuring Success
@@ -36,7 +36,7 @@ One thing that doesn't change: context window size matters for your workflow.
- **Large codebases**: 256K+ tokens helps with cross-system understanding
- **Massive systems**: 1M+ token models exist but effectiveness degrades at the extremes
Check [our provider docs](/docs/basic-usage/connecting-providers) for specific context limits on each model.
Check [our provider docs](/docs/ai-providers) for specific context limits on each model.
{% callout type="tip" %}
**Be thoughtful about Max Tokens settings for thinking models.** Every token you allocate to output takes away from space available to store conversation history. Consider only using high `Max Tokens` / `Max Thinking Tokens` settings with modes like Architect and Debug, and keeping Code mode at 16k max tokens or less.
@@ -25,7 +25,7 @@ Orchestrator Mode (formerly known as Boomerang Tasks) allows you to break down c
## Key Considerations
- **Approval Required:** By default, you must approve the creation and completion of each subtask. This can be automated via the [Auto-Approving Actions](/docs/features/auto-approving-actions#subtasks) settings if desired.
- **Approval Required:** By default, you must approve the creation and completion of each subtask. This can be automated via the [Auto-Approving Actions](/docs/getting-started/settings/auto-approving-actions#subtasks) settings if desired.
- **Context Isolation and Transfer:** Each subtask operates in complete isolation with its own conversation history. It does not automatically inherit the parent's context. Information must be explicitly passed:
- **Down:** Via the initial instructions provided when the subtask is created.
- **Up:** Via the final summary provided when the subtask finishes. Be mindful that only this summary returns to the parent.
@@ -37,6 +37,6 @@ Orchestrator Mode provides a powerful way to manage complex development workflow
Use subtasks to maintain clarity. If a request significantly shifts focus or requires a different expertise (mode), consider creating a subtask rather than overloading the current one.
{% /callout %}
1. This context is passed via the `message` parameter of the [`new_task`](/docs/features/tools/new-task) tool.
2. The mode for the subtask is specified via the `mode` parameter of the [`new_task`](/docs/features/tools/new-task) tool during initiation.
3. This summary is passed via the `result` parameter of the [`attempt_completion`](/docs/features/tools/attempt-completion) tool when the subtask finishes.
1. This context is passed via the `message` parameter of the [`new_task`](/docs/automate/tools/new-task) tool.
2. The mode for the subtask is specified via the `mode` parameter of the [`new_task`](/docs/automate/tools/new-task) tool during initiation.
3. This summary is passed via the `result` parameter of the [`attempt_completion`](/docs/automate/tools/attempt-completion) tool when the subtask finishes.
@@ -114,4 +114,4 @@ If using Cursor, go to **Settings** > **Cursor Settings** > **Tab**, and toggle
## Related Features
- [Code Actions](/docs/features/code-actions) - Context menu options for common coding tasks
- [Code Actions](/docs/code-with-ai/features/code-actions) - Context menu options for common coding tasks
@@ -23,7 +23,7 @@ When **Enable editing through diffs** is checked:
2. **Prevents Truncated Writes**: The system automatically detects and rejects attempts by the AI to write incomplete file content, which can happen with large files or complex instructions. This helps prevent corrupted files.
{% callout type="note" title="Disabling Fast Edits" %}
If you uncheck **Enable editing through diffs**, Kilo will revert to writing the entire file content for every edit using the [`write_to_file`](/docs/features/tools/write-to-file) tool, instead of applying targeted changes with [`apply_diff`](/docs/features/tools/apply-diff). This full-write approach is generally slower for modifying existing files and leads to higher token usage.
If you uncheck **Enable editing through diffs**, Kilo will revert to writing the entire file content for every edit using the [`write_to_file`](/docs/automate/tools/write-to-file) tool, instead of applying targeted changes with [`apply_diff`](/docs/automate/tools/apply-diff). This full-write approach is generally slower for modifying existing files and leads to higher token usage.
{% /callout %}
## Match Precision
@@ -21,7 +21,7 @@ description: "Track and manage tasks with AI-generated todo lists"
**Manual triggers**:
- Ask Kilo to "use the [update_todo_list tool](/docs/features/tools/update-todo-list)"
- Ask Kilo to "use the [update_todo_list tool](/docs/automate/tools/update-todo-list)"
- Say "create a todo list"
**The bottom line**: Kilo decides what goes in the list, but you can provide feedback during approval dialogs.
@@ -30,7 +30,7 @@ description: "Track and manage tasks with AI-generated todo lists"
## How todo lists are updated
Todo lists are managed with the [`update_todo_list` tool](/docs/features/tools/update-todo-list). Each time Kilo updates the list, it replaces the entire checklist with the latest view of the task.
Todo lists are managed with the [`update_todo_list` tool](/docs/automate/tools/update-todo-list). Each time Kilo updates the list, it replaces the entire checklist with the latest view of the task.
Kilo updates the list when:
@@ -113,7 +113,7 @@ You can disable todo lists in Settings -> Advanced -> **Enable todo list tool**.
**When to use it**: Long workflows where constant interruptions slow you down.
**How to enable it**: Check the [Update Todo List auto-approval settings](/docs/features/auto-approving-actions#update-todo-list).
**How to enable it**: Check the [Update Todo List auto-approval settings](/docs/getting-started/settings/auto-approving-actions#update-todo-list).
**The catch**: Less control, but faster execution.
{% /callout %}
@@ -167,7 +167,7 @@ Review your code locally before pushing — catch issues early without waiting f
Configuration is managed through:
- `/connect` command for provider setup (interactive)
- Config files in **`~/.config/kilo/`**: the CLI (Kilo CLI 1.0 from [Kilo-Org/kilo](https://github.com/Kilo-Org/kilo)) merges `config.json`, `opencode.json`, and `opencode.jsonc`. Use **`opencode.json`** (or `opencode.jsonc`) for provider, model, permission, and **MCP** settings. Restart the CLI after editing. See [Using MCP in the CLI](/automate/mcp/using-in-cli) for MCP config format.
- Config files in **`~/.config/kilo/`**: the CLI (Kilo CLI 1.0 from [Kilo-Org/kilo](https://github.com/Kilo-Org/kilo)) merges `config.json`, `opencode.json`, and `opencode.jsonc`. Use **`opencode.json`** (or `opencode.jsonc`) for provider, model, permission, and **MCP** settings. Restart the CLI after editing. See [Using MCP in the CLI](/docs/automate/mcp/using-in-cli) for MCP config format.
- `kilo auth` for credential management
## Slash Commands
@@ -345,20 +345,6 @@ Use `{env:VARIABLE_NAME}` syntax in config files to reference environment variab
For full details on all configuration options including compaction, file watchers, plugins, and experimental features, see the [OpenCode Config documentation](https://opencode.ai/docs/config).
## Config reference for providers
Kilo gives you the ability to bring your own keys for a number of model providers and AI gateways, like OpenRouter and Vercel AI Gateway. Each provider has unique configuration options and some let you set environment variables.
You can reference the [Provider Configuration Guide](https://github.com/Kilo-Org/kilocode/blob/main/cli/docs/PROVIDER_CONFIGURATION.md) for examples (same config format; for Kilo CLI 1.0 the file is `~/.config/kilo/opencode.json`). You can also run:
`kilo config`
to complete configuration with an interactive workflow on the command line.
{% callout type="tip" %}
You can also use the `/config` slash command during an interactive session, which is equivalent to running `kilocode config`.
{% /callout %}
## Interactive Mode
Interactive mode is the default mode when running Kilo Code without the `--auto` flag, designed to work interactively with a user through the console.
@@ -85,6 +85,15 @@ You can customize each Cloud Agent session by also defining env vars and startup
- Bootstrapping tooling
- Running setup scripts
### Setup Commands vs `.kilocode/setup-script`
- Cloud Agent executes **Setup Commands** configured in the Cloud UI/profile.
- Cloud Agent does **not** automatically discover or run `.kilocode/setup-script`.
- If you want to use `.kilocode/setup-script` in Cloud Agent, call it explicitly from Setup Commands, for example: `bash .kilocode/setup-script`.
- If both are present, execution order is:
1. Setup Commands (in the order you define them)
2. Anything those commands invoke (such as `.kilocode/setup-script`)
## Skills
Cloud Agents support project-level [skills](/docs/code-with-ai/platforms/cli#skills) stored in your repository. When your repo is cloned, any skills in `.kilocode/skills/` are automatically available.
@@ -71,7 +71,7 @@ Low Depth indicates that developers may be trying AI but not trusting or shippin
**Actions:**
1. Enable [Managed Indexing](/docs/advanced-usage/managed-indexing) to improve context quality
1. Enable [Managed Indexing](/docs/deploy-secure/managed-indexing) to improve context quality
2. Review whether suggestions are relevant to your codebase
3. Introduce chained workflows to increase multi-stage usage
@@ -235,6 +235,6 @@ Additional views for comparing multiple teams within an organization are planned
## Next Steps
- [Understand what each dimension measures](/docs/plans/adoption-dashboard/understanding-your-score)
- [Learn strategies to improve your score](/docs/plans/adoption-dashboard/improving-your-score)
- [Return to the dashboard overview](/docs/plans/adoption-dashboard/overview)
- [Understand what each dimension measures](/docs/collaborate/adoption-dashboard/understanding-your-score)
- [Learn strategies to improve your score](/docs/collaborate/adoption-dashboard/improving-your-score)
- [Return to the dashboard overview](/docs/collaborate/adoption-dashboard/overview)
@@ -73,7 +73,7 @@ Linking coding → review → deploy actions significantly boosts your Depth sco
If acceptance rates are low, the issue is often context. The AI is making suggestions without understanding your codebase.
**Action:** Enable [Managed Indexing](/docs/advanced-usage/managed-indexing) to give the model vector-backed search across your repository.
**Action:** Enable [Managed Indexing](/docs/deploy-secure/managed-indexing) to give the model vector-backed search across your repository.
Better context leads to:
@@ -86,7 +86,7 @@ Better context leads to:
Generated code that never runs is hard to trust. Teams that can verify AI output against live environments tend to retain more of that code long-term.
**Action:** Use [Kilo Deploy](/docs/advanced-usage/deploy) to spin up live URLs for branches, allowing your team to verify changes before merging.
**Action:** Use [Kilo Deploy](/docs/deploy-secure/deploy) to spin up live URLs for branches, allowing your team to verify changes before merging.
---
@@ -190,5 +190,5 @@ Other ways to spread usage:
## Next Steps
- [Use the dashboard for team leadership](/docs/plans/adoption-dashboard/for-team-leads)
- [Return to the dashboard overview](/docs/plans/adoption-dashboard/overview)
- [Use the dashboard for team leadership](/docs/collaborate/adoption-dashboard/for-team-leads)
- [Return to the dashboard overview](/docs/collaborate/adoption-dashboard/overview)
@@ -92,6 +92,6 @@ Click on any dimension card to view detailed analysis and improvement suggestion
## Next Steps
- [Understand what each dimension measures](/docs/plans/adoption-dashboard/understanding-your-score)
- [Learn strategies to improve your score](/docs/plans/adoption-dashboard/improving-your-score)
- [Use the dashboard for team leadership](/docs/plans/adoption-dashboard/for-team-leads)
- [Understand what each dimension measures](/docs/collaborate/adoption-dashboard/understanding-your-score)
- [Learn strategies to improve your score](/docs/collaborate/adoption-dashboard/improving-your-score)
- [Use the dashboard for team leadership](/docs/collaborate/adoption-dashboard/for-team-leads)
@@ -147,5 +147,5 @@ Individual scores are most useful for personal development and self-assessment,
## Next Steps
- [Learn strategies to improve each dimension](/docs/plans/adoption-dashboard/improving-your-score)
- [Use the dashboard for team leadership](/docs/plans/adoption-dashboard/for-team-leads)
- [Learn strategies to improve each dimension](/docs/collaborate/adoption-dashboard/improving-your-score)
- [Use the dashboard for team leadership](/docs/collaborate/adoption-dashboard/for-team-leads)
@@ -46,5 +46,5 @@ Here is the list of all events included in the Kilo Code audit logs:
- Organization: Create, Settings Change, Purchase Credits
- Organization Member: Remove, Change Role
- User: Login, Logout, Accept Invite, Send Invite, Revoke Invite
- [Custom Modes](/docs/plans/custom-modes): Create, Update, Delete
- [SSO](/docs/plans/enterprise/SSO) (Enterprise Only): Auto Provision, Set Domain, Remove Domain
- [Custom Modes](/docs/collaborate/teams/custom-modes-org): Create, Update, Delete
- [SSO](/docs/collaborate/enterprise/sso) (Enterprise Only): Auto Provision, Set Domain, Remove Domain
@@ -57,7 +57,7 @@ Switch to **Kilo Teams** or **Kilo Enterprise** from other AI coding tools and e
**Step 2: Kilo Setup**
1. **Create organization** at [app.kilocode.com](https://app.kilocode.com)
1. **Create organization** at [app.kilo.ai](https://app.kilo.ai)
2. **Subscribe to Teams ($15/user/month)** or **Enterprise ([Contact Sales](https://kilo.ai/contact-sales))**
3. **Configure team settings** and usage policies
4. **Purchase initial AI credits** based on usage estimates
@@ -355,7 +355,7 @@ Kilo Code also supports mode-specific rules (`.kilocode/rules-{mode}/`), which C
- **Discord:** Join our migration support channel
- **Consultation:** Schedule free migration planning call
- **Documentation:**
- [Business migration guide](/docs/plans/migration) (this page)
- [Business migration guide](/docs/collaborate/enterprise/migration) (this page)
- [Technical migration guide](/docs/getting-started/migrating) (rules and configurations)
## Success Stories
@@ -383,9 +383,9 @@ Kilo Code also supports mode-specific rules (`.kilocode/rules-{mode}/`), which C
## Next Steps
- [Get started with your team](/docs/plans/getting-started)
- [Explore team management features](/docs/plans/team-management)
- [Understand billing and pricing](/docs/plans/billing)
- [Get started with your team](/docs/collaborate/teams/getting-started)
- [Explore team management features](/docs/collaborate/teams/team-management)
- [Understand billing and pricing](/docs/collaborate/teams/billing)
- [Migrate your rules and configurations](/docs/getting-started/migrating) (technical guide)
Ready to make the switch? Contact our migration team at migrations@kilo.ai to plan your transition to transparent AI coding.
@@ -41,5 +41,5 @@ Fill in your contact information and someone from our team will reach out soon t
After enabling SSO:
- Invite new users with their company email domain.
- Manage team access and roles from the **[Organization](/docs/plans/dashboard)** tab.
- View user activity across the team in the **[Audit Logs](/docs/plans/enterprise/audit-logs)** tab
- Manage team access and roles from the **[Organization](/docs/collaborate/adoption-dashboard/overview)** tab.
- View user activity across the team in the **[Audit Logs](/docs/collaborate/enterprise/audit-logs)** tab
@@ -129,7 +129,7 @@ All costs are displayed in USD with detailed precision, helping you:
## Next Steps
- [Manage team billing settings](/docs/plans/billing)
- [Configure team roles and permissions](/docs/plans/team-management)
- [Manage team billing settings](/docs/collaborate/teams/billing)
- [Configure team roles and permissions](/docs/collaborate/teams/team-management)
The usage analytics provide the insights needed to optimize your team's AI usage while maintaining visibility into costs and activity patterns.
@@ -21,7 +21,7 @@ Organization Owners can purchase Kilo credits on the [Organization dashboard](ht
Organization credits are purchased on behalf of all users in the organization. Every member of the organization can use the credits in the organization's balance with the Kilo Code model provider.
Using organization credits works exactly like spending [individual credits](/docs/basic-usage/adding-credits), except that the credits come from the organization's credit balance, rather than the individuals.
Using organization credits works exactly like spending [individual credits](/docs/getting-started/adding-credits), except that the credits come from the organization's credit balance, rather than the individuals.
### Buying Organization Credits
@@ -47,7 +47,7 @@ You can remove empty seats at any time. Your next payment will reflect the small
Your next billing date will not change.
To fill empty seats or remove members ahead of seat deletion, see the [team management](/docs/plans/team-management) page.
To fill empty seats or remove members ahead of seat deletion, see the [team management](/docs/collaborate/teams/team-management) page.
### Adding Seats
@@ -64,7 +64,7 @@ To fill empty seats or remove members ahead of seat deletion, see the [team mana
3. **Select seats to remove** (must remove team members first)
4. **Confirm reduction**
To fill empty seats or remove members ahead of seat deletion, see the [team management](/docs/plans/team-management) page.
To fill empty seats or remove members ahead of seat deletion, see the [team management](/docs/collaborate/teams/team-management) page.
## Invoices
@@ -81,6 +81,6 @@ If payment fails repeatedly:
## Next Steps
- [Explore usage analytics](/docs/plans/analytics)
- [Learn about team roles and permissions](/docs/plans/team-management)
- [Learn about team management](/docs/plans/team-management)
- [Explore usage analytics](/docs/collaborate/teams/analytics)
- [Learn about team roles and permissions](/docs/collaborate/teams/team-management)
- [Learn about team management](/docs/collaborate/teams/team-management)
@@ -162,6 +162,6 @@ Manage your Kilo Teams plan and seat allocation.
## Next Steps
- [Learn about team management](/docs/plans/team-management)
- [Understand billing and credits](/docs/plans/billing)
- [Explore usage analytics](/docs/plans/analytics)
- [Learn about team management](/docs/collaborate/teams/team-management)
- [Understand billing and credits](/docs/collaborate/teams/billing)
- [Explore usage analytics](/docs/collaborate/teams/analytics)
@@ -76,6 +76,6 @@ You can find the dedicated Teams support methods directly on your Organization's
## Next Steps
- [Learn about team roles and permissions](/docs/plans/team-management)
- [Explore the dashboard features](/docs/plans/dashboard)
- [Set up team management policies](/docs/plans/team-management)
- [Learn about team roles and permissions](/docs/collaborate/teams/team-management)
- [Explore the dashboard features](/docs/collaborate/adoption-dashboard/overview)
- [Set up team management policies](/docs/collaborate/teams/team-management)
@@ -11,7 +11,7 @@ Owners have full administrative oversight including billing, seat allocation, an
Only Owners can conduct team management activities.
Members can use the Kilo Code extension and see data on the team's usage in the [usage dashboard](/docs/plans/analytics).
Members can use the Kilo Code extension and see data on the team's usage in the [usage dashboard](/docs/collaborate/teams/analytics).
## Adding Team Members
@@ -53,8 +53,8 @@ The Organization tab shows:
## Next Steps
- [Understand billing and credits](/docs/plans/billing)
- [Explore usage analytics](/docs/plans/analytics)
- [Learn about team roles and permissions](/docs/plans/team-management)
- [Understand billing and credits](/docs/collaborate/teams/billing)
- [Explore usage analytics](/docs/collaborate/teams/analytics)
- [Learn about team roles and permissions](/docs/collaborate/teams/team-management)
Effective team management ensures your organization maximizes the benefits of AI-assisted development while maintaining cost control and security.
@@ -11,7 +11,6 @@ These pages document the architecture and design of current or planned features,
| ---------------------------------------------------------------------------------------- | ------------------------------------------------ |
| [Agent Observability](/docs/contributing/architecture/agent-observability) | Observability and monitoring for agentic systems |
| [Benchmarking](/docs/contributing/architecture/benchmarking) | Benchmarking Kilo Code across models and agents |
| [Annual Billing](/docs/contributing/architecture/annual-billing) | Annual subscription billing |
| [Enterprise MCP Controls](/docs/contributing/architecture/enterprise-mcp-controls) | Admin controls for MCP server allowlists |
| [MCP OAuth Authorization](/docs/contributing/architecture/mcp-oauth-authorization) | OAuth 2.1-based authorization for MCP servers |
| [Onboarding Improvements](/docs/contributing/architecture/onboarding-improvements) | User onboarding and engagement features |
@@ -144,4 +144,4 @@ The project uses:
## Further Reading
- [Development Environment](/docs/contributing/development-environment) - Setup guide
- [Tools Reference](/docs/features/tools/tool-use-overview) - Available tools
- [Tools Reference](/docs/automate/tools) - Available tools
@@ -9,8 +9,6 @@ description: "Set up your development environment for contributing"
**New versions of the VS Code extension and CLI are being developed in [Kilo-Org/Kilo](https://github.com/Kilo-Org/Kilo)** (extension at `packages/kilo-vscode`, CLI at `packages/opencode`). For extension and CLI development, please head over to that repository.
{% /callout %}
<!-- Please refer to the [DEVELOPMENT.md](https://github.com/Kilo-Org/kilocode/blob/main/DEVELOPMENT.md) guide in the main repository for detailed instructions on setting up the development environment. -->
This document will help you set up your development environment and understand how to work with the codebase. Whether you're fixing bugs, adding features, or just exploring the code, this guide will get you started.
## Prerequisites
@@ -18,7 +16,7 @@ This document will help you set up your development environment and understand h
Before you begin, make sure you have the following installed:
1. **Git** - For version control
2. **Node.js** (version [v20.18.1](https://github.com/Kilo-Org/kilocode/blob/main/.nvmrc) or higher recommended) and npm
2. **Node.js** (version v20.18.1 (See `.nvmrc` for latest) or higher recommended) and npm
3. **Visual Studio Code** - Our recommended IDE for development
## Getting Started
@@ -27,12 +25,12 @@ Before you begin, make sure you have the following installed:
1. **Fork and Clone the Repository**:
- **Fork the Repository**:
- Visit the [Kilo Code GitHub repository](https://github.com/Kilo-Org/kilocode)
- Visit the [Kilo Code GitHub repository](https://github.com/Kilo-Org/kilo)
- Click the "Fork" button in the top-right corner to create your own copy.
- **Clone Your Fork**:
```bash
git clone https://github.com/[YOUR-USERNAME]/kilocode.git
cd kilocode
git clone https://github.com/[YOUR-USERNAME]/kilo.git
cd kilo
```
Replace `[YOUR-USERNAME]` with your actual GitHub username.
@@ -52,7 +50,7 @@ While not strictly necessary for running the extension, these extensions are rec
- [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) - Integrates ESLint into VS Code.
- [Prettier - Code formatter](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) - Integrates Prettier into VS Code.
The full list of recommended extensions is [here](https://github.com/Kilo-Org/kilocode/blob/main/.vscode/extensions.json)
The full list of recommended extensions is in `.vscode/extensions.json`
### Project Structure
@@ -151,7 +149,7 @@ E2E tests verify the extension works correctly within VSCode:
npm run test:integration
```
For more details on E2E tests, see [e2e/VSCODE_INTEGRATION_TESTS.md](https://github.com/Kilo-Org/kilocode/blob/main/e2e/VSCODE_INTEGRATION_TESTS.md).
For more details on E2E tests, see e2e/VSCODE_INTEGRATION_TESTS
## Linting and Type Checking
@@ -141,7 +141,7 @@ If you need help with your contribution:
- Join our [Discord community](https://kilo.ai/discord) for real-time support
- Ask questions on [GitHub Discussions](https://github.com/Kilo-Org/kilocode/discussions)
- Visit our [Reddit community](https://www.reddit.com/r/KiloCode)
- Visit our [Reddit community](https://www.reddit.com/r/kilocode)
## Recognition
@@ -74,7 +74,7 @@ You can configure context condensing thresholds and behavior on a per-profile ba
### Maintaining Context Quality
- **Be specific in your initial task**: A clear task description helps create better summaries
- **Use Memory Bank**: Combine with [Memory Bank](/docs/customize/context/memory-bank) for persistent project context that doesn't need to be condensed
- **Use AGENTS.md**: Combine with [AGENTS.md](/docs/customize/agents-md) for persistent project context that doesn't need to be condensed
- **Review the summary**: After condensing, the summary is visible in your chat history
## Troubleshooting
@@ -97,6 +97,6 @@ If the condensed summary doesn't capture important details:
## Related Features
- [Memory Bank](/docs/customize/context/memory-bank) - Persistent context storage across sessions
- [AGENTS.md](/docs/customize/agents-md) - Persistent context storage across sessions
- [Large Projects](/docs/customize/context/large-projects) - Managing context for large codebases
- [Codebase Indexing](/docs/customize/context/codebase-indexing) - Efficient code search and retrieval
@@ -21,7 +21,7 @@ Custom Instructions are IDE-wide and are applied across all workspaces and maint
{% image src="/docs/img/custom-instructions/custom-instructions.png" alt="Kilo Code Modes tab showing global custom instructions interface" width="600" caption="Kilo Code Modes tab showing global custom instructions interface" /%}
1. **Open Modes Tab:** Click the <Codicon name="organization" /> icon in the Kilo Code top menu bar
1. **Open Modes Tab:** Click the <Codicon name="notebook" /> icon in the Kilo Code top menu bar
2. **Find Section:** Find the "Custom Instructions for All Modes" section
3. **Enter Instructions:** Enter your instructions in the text area
4. **Save Changes:** Click "Done" to save your changes
@@ -31,7 +31,7 @@ Custom Instructions are IDE-wide and are applied across all workspaces and maint
Mode-specific instructions can be set using the Modes Tab
{% image src="/docs/img/custom-instructions/custom-instructions-3.png" alt="Kilo Code Modes tab showing mode-specific custom instructions interface" width="600" caption="Kilo Code Modes tab showing mode-specific custom instructions interface" /%}
* **Open Tab:** Click the <Codicon name="organization" /> icon in the Kilo Code top menu bar
* **Open Tab:** Click the <Codicon name="notebook" /> icon in the Kilo Code top menu bar
* **Select Mode:** Under the Modes heading, click the button for the mode you want to customize
* **Enter Instructions:** Enter your instructions in the text area under "Mode-specific Custom Instructions (optional)"
* **Save Changes:** Click "Done" to save your changes
@@ -40,9 +40,20 @@ Mode-specific instructions can be set using the Modes Tab
If the mode itself is global (not workspace-specific), any custom instructions you set for it will also apply globally for that mode across all workspaces.
{% /callout %}
## Mode-Specific Instructions from Files
For version-controlled mode instructions, use the mode rules file paths documented in [Custom Modes](/docs/customize/custom-modes#mode-specific-instructions-via-filesdirectories):
- Preferred: `.kilo/rules-{mode-slug}/` (directory)
- Fallback: `.kilorules-{mode-slug}` (single file)
{% callout type="info" title="Legacy Naming Note" %}
Older naming like `.clinerules-{mode-slug}` is not the recommended path for current Kilo mode-specific instructions.
{% /callout %}
## Related Features
- [Custom Modes](/docs/customize/custom-modes)
- [Custom Rules](/docs/customize/custom-rules)
- [Settings Management](/docs/getting-started/settings)
- [Auto-Approval Settings](/docs/features/auto-approving-actions)
- [Auto-Approval Settings](/docs/getting-started/settings/auto-approving-actions)
@@ -74,7 +74,7 @@ Modes are managed from the Modes area in Kilo Code. Depending on your UI layout,
1. Open the Modes area from the mode selector in the chat panel (or via the <Codicon name="notebook" /> icon if shown)
2. Click the Import Mode button (upload icon)
3. Select the mode's YAML file
3. Select the mode's YAML file (`.yaml`)
4. Choose the import level:
- **Project:** Available only in current workspace (saved to `.kilocodemodes` file)
- **Global:** Available in all projects (saved to global settings)
@@ -121,11 +121,16 @@ The interface provides fields for Name, Slug, Description, Save Location, Role D
You can directly edit the configuration files to create or modify custom modes. This method offers the most control over all properties. Kilo Code now supports both YAML (preferred) and JSON formats.
- **Global Modes:** Edit the `custom_modes.yaml` (preferred) or `custom_modes.json` file. Open the Modes area, click <Codicon name="gear" /> next to Global Modes, then choose "Edit Global Modes"
- **Project Modes:** Edit the `.kilocodemodes` file (which can be YAML or JSON) in your project root. Open the Modes area, click <Codicon name="gear" /> next to Project Modes, then choose "Edit Project Modes"
- **Global Modes:** Edit `custom_modes.yaml` (primary). `custom_modes.json` is a legacy fallback and may still exist in older setups.
- **Project Modes:** Edit `.kilocodemodes` in your project root (YAML preferred; JSON still supported for compatibility).
- **Open from UI:** Open the Modes area, click <Codicon name="gear" /> next to Global or Project Modes, then choose **Edit Global Modes** or **Edit Project Modes**.
These files define an array/list of custom modes.
{% callout type="info" title="Why JSON Files May Still Exist" %}
If you see both YAML and JSON mode files, this is usually from legacy configuration. Kilo Code reads YAML first and does not keep both files synchronized line-by-line. In practice, edit YAML unless you have a specific reason to stay on JSON.
{% /callout %}
## YAML Configuration Format (Preferred)
YAML is now the preferred format for defining custom modes due to better readability, comment support, and cleaner multi-line strings.
@@ -221,4 +221,4 @@ If your custom rules aren't being properly followed:
- [Custom Modes](/docs/customize/custom-modes)
- [Custom Instructions](/docs/customize/custom-instructions)
- [Settings Management](/docs/getting-started/settings)
- [Auto-Approval Settings](/docs/features/auto-approving-actions)
- [Auto-Approval Settings](/docs/getting-started/settings/auto-approving-actions)
+1 -1
View File
@@ -27,7 +27,7 @@ Help Kilo understand your codebase better:
- [**Codebase Indexing**](/docs/customize/context/codebase-indexing) - Build a semantic index of your code for better context awareness
- [**Context Condensing**](/docs/customize/context/context-condensing) - Summarize older context to stay within limits
- [**Memory Bank**](/docs/customize/context/memory-bank) - Store project context, decisions, and important information
- [**AGENTS.md**](/docs/customize/agents-md) - Store project context, decisions, and important information
- [**Large Projects**](/docs/customize/context/large-projects) - Best practices for working with monorepos and large codebases
## Getting Started
@@ -13,7 +13,7 @@ Prompt engineering is the art of crafting effective instructions for AI models l
- **Bad:** Fix the code.
- **Good:** Fix the bug in the `calculateTotal` function that causes it to return incorrect results.
- **Provide Context:** Use [Context Mentions](/docs/basic-usage/context-mentions) to refer to specific files, folders, or problems.
- **Provide Context:** Use [Context Mentions](/docs/code-with-ai/agents/context-mentions) to refer to specific files, folders, or problems.
- **Good:** `@/src/utils.ts` Refactor the `calculateTotal` function to use async/await.
- **Break Down Tasks:** Divide complex tasks into smaller, well-defined steps.
@@ -26,10 +26,10 @@ Workflows are markdown files stored in `.kilocode/workflows/`:
Workflows can leverage:
- [Built-in tools](/docs/features/tools/tool-use-overview): [`read_file()`](/docs/features/tools/read-file), [`search_files()`](/docs/features/tools/search-files), [`execute_command()`](/docs/features/tools/execute-command)
- [Built-in tools](/docs/automate/tools): [`read_file()`](/docs/automate/tools/read-file), [`search_files()`](/docs/automate/tools/search-files), [`execute_command()`](/docs/automate/tools/execute-command)
- CLI tools: `gh`, `docker`, `npm`, custom scripts
- [MCP integrations](/docs/automate/mcp/overview): Slack, databases, APIs
- [Mode switching](/docs/code-with-ai/agents/using-modes): [`new_task()`](/docs/features/tools/new-task) for specialized contexts
- [Mode switching](/docs/code-with-ai/agents/using-modes): [`new_task()`](/docs/automate/tools/new-task) for specialized contexts
## Common Workflow Patterns
@@ -9,7 +9,7 @@ description: "Get up and running with Kilo Code in minutes"
{% youtube url="https://www.youtube.com/watch?v=pO7zRLQS-p0" caption="This quick tour shows how Kilo Code handles a simple request from start to finish" /%}
After you [set up Kilo Code](/docs/getting-started/setting-up), follow these steps:
After you [set up Kilo Code](/docs/getting-started/setup-authentication), follow these steps:
## Step by Step Guide
@@ -30,7 +30,7 @@ Type a clear, concise description of what you want Kilo Code to do in the chat b
No special commands or syntax needed—just use plain English.
{% callout type="tip" title="Optional: Try Autocomplete" collapsed=true %}
While chat is great for complex tasks, Kilo Code also offers **inline autocomplete** for quick code suggestions. Open any code file, start typing, and watch for ghost text suggestions. Press `Tab` to accept. [Learn more about Autocomplete →](/docs/basic-usage/autocomplete)
While chat is great for complex tasks, Kilo Code also offers **inline autocomplete** for quick code suggestions. Open any code file, start typing, and watch for ghost text suggestions. Press `Tab` to accept. [Learn more about Autocomplete →](/docs/code-with-ai/features/autocomplete)
{% /callout %}
{% image src="/docs/img/your-first-task/your-first-task-6.png" alt="Typing a task in the Kilo Code chat interface" width="500" caption="Enter your task in natural language - no special syntax required." /%}
@@ -57,7 +57,7 @@ Kilo Code analyzes your request and proposes specific actions. These may include
{% callout type="tip" %}
The level of autonomy is configurable, allowing you to make the agent more or less autonomous.
You can learn more about [using modes](/docs/code-with-ai/agents/using-modes) and [auto-approving actions](/docs/features/auto-approving-actions).
You can learn more about [using modes](/docs/code-with-ai/agents/using-modes) and [auto-approving actions](/docs/getting-started/settings/auto-approving-actions).
{% /callout %}
### Step 5: Iterate
@@ -46,6 +46,6 @@ If you set the rate limit to 10 seconds, Kilo Code will wait at least 10 seconds
- **Use Custom Instructions:** Provide custom instructions to guide Kilo Code's behavior and reduce the need for lengthy explanations in each prompt.
- **Choose the Right Model:** Some models are more cost-effective than others. Consider using a smaller, faster model for tasks that don't require the full power of a larger model.
- **Use Modes:** Different modes can access different tools, for example `Architect` can't modify code, which makes it a safe choice when analyzing a complex codebase, without worrying about accidentally allowing expensive operations.
- **Disable MCP If Not Used:** If you're not using MCP (Model Context Protocol) features, consider [disabling it in Settings > Agent Behaviour > MCP Servers](/automate/mcp/overview) to significantly reduce the size of the system prompt and save tokens.
- **Disable MCP If Not Used:** If you're not using MCP (Model Context Protocol) features, consider [disabling it in Settings > Agent Behaviour > MCP Servers](/docs/automate/mcp/overview) to significantly reduce the size of the system prompt and save tokens.
By understanding and managing your API usage, you can use Kilo Code effectively and efficiently.
@@ -41,7 +41,7 @@ Every task is automatically classified into one of these categories:
#### Understanding Task Completion
A task is considered "completed" when Kilo Code uses the [`attempt_completion`](/automate/tools/attempt-completion) tool to formally mark it as finished. Tasks without this completion marker are classified as incomplete, even if you consider them done. This distinction helps clean up abandoned or experimental tasks more aggressively.
A task is considered "completed" when Kilo Code uses the [`attempt_completion`](/docs/automate/tools/attempt-completion) tool to formally mark it as finished. Tasks without this completion marker are classified as incomplete, even if you consider them done. This distinction helps clean up abandoned or experimental tasks more aggressively.
### Cleanup Process
@@ -102,7 +102,7 @@ Default: 30 days
Minimum: 1 day
```
Tasks successfully completed via the [`attempt_completion`](/automate/tools/attempt-completion) tool are retained for this period. These tasks typically represent finished work that may still be useful for reference.
Tasks successfully completed via the [`attempt_completion`](/docs/automate/tools/attempt-completion) tool are retained for this period. These tasks typically represent finished work that may still be useful for reference.
#### Incomplete Tasks
@@ -240,9 +240,9 @@ Task data is stored in your VS Code global storage location:
## Related Features
- [**Checkpoints**](/code-with-ai/features/checkpoints): Version control for tasks that can be restored
- [**Settings Management**](/getting-started/settings): Export/import settings including cleanup configuration
- [**Task History**](/code-with-ai/agents/chat-interface): Managing and organizing your task history
- [**Checkpoints**](/docs/code-with-ai/features/checkpoints): Version control for tasks that can be restored
- [**Settings Management**](/docs/getting-started/settings): Export/import settings including cleanup configuration
- [**Task History**](/docs/code-with-ai/agents/chat-interface): Managing and organizing your task history
## Frequently Asked Questions
@@ -47,7 +47,7 @@ These are just a few examples! Kilo Code supports many more providers including
### ChatGPT Plus/Pro Subscription
Already have a ChatGPT subscription? You can use it with Kilo Code through the [OpenAI ChatGPT provider](/docs/providers/openai-chatgpt-plus-pro)—no API key needed.
Already have a ChatGPT subscription? You can use it with Kilo Code through the [OpenAI ChatGPT provider](/docs/ai-providers/openai-chatgpt-plus-pro)—no API key needed.
### OpenRouter
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@kilocode/kilo-gateway",
"version": "1.0.24",
"version": "1.0.25",
"type": "module",
"license": "MIT",
"description": "Unified Kilo Gateway package for OpenCode - authentication, provider, and API integration",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@kilocode/kilo-i18n",
"version": "1.0.24",
"version": "1.0.25",
"type": "module",
"license": "MIT",
"description": "Kilo-specific i18n translations and overrides",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://json.schemastore.org/package.json",
"name": "@kilocode/kilo-telemetry",
"version": "1.0.24",
"version": "1.0.25",
"type": "module",
"license": "MIT",
"description": "Telemetry for Kilo CLI - PostHog analytics integration",
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@kilocode/kilo-ui",
"version": "1.0.24",
"version": "1.0.25",
"type": "module",
"license": "MIT",
"exports": {
@@ -2,4 +2,32 @@
.shiki {
margin: 0rem;
}
pre {
scrollbar-width: thin;
scrollbar-color: var(--border-weak-base) transparent;
&::-webkit-scrollbar-track {
background: transparent;
}
&::-webkit-scrollbar-corner {
background: transparent;
}
&::-webkit-scrollbar-button {
display: none;
width: 0;
height: 0;
}
&::-webkit-scrollbar-thumb {
background: var(--border-weak-base);
border-radius: 4px;
&:hover {
background: var(--border-strong-base);
}
}
}
}
@@ -5,4 +5,8 @@
[data-slot="text-part-body"] {
margin-top: 0;
}
[data-slot="text-part-copy-wrapper"] {
display: none;
}
}
+4 -2
View File
@@ -49,7 +49,8 @@
}
::-webkit-scrollbar-button {
display: block;
display: none;
width: 0;
height: 0;
}
@@ -63,7 +64,8 @@ html[data-theme="kilo-vscode"] {
font-weight: var(--vscode-font-weight);
::-webkit-scrollbar-button {
display: block;
display: none;
width: 0;
height: 0;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

+12 -4
View File
@@ -1,8 +1,9 @@
{
"name": "kilo-code",
"displayName": "Kilo Code",
"description": "Kilo Code AI Agent & Autocomplete",
"version": "7.0.24",
"displayName": "Kilo Code: AI Coding Agent, Copilot, and Autocomplete",
"description": "Open Source AI coding agent that generates code from natural language, automates tasks, and runs terminal commands. Features inline autocomplete, browser automation, automated refactoring, and custom modes for planning, coding, and debugging. Supports 500+ AI models including Claude (Anthropic), Gemini, Grok, GPT, Codex and GLM.",
"version": "7.0.25",
"icon": "assets/icons/logo-outline-black.png",
"publisher": "kilocode",
"repository": {
"type": "git",
@@ -291,6 +292,11 @@
"key": "ctrl+shift+a",
"mac": "cmd+shift+a"
},
{
"command": "kilo-code.new.agentManagerOpen",
"key": "ctrl+shift+m",
"mac": "cmd+shift+m"
},
{
"command": "kilo-code.new.addToContext",
"key": "ctrl+k ctrl+a",
@@ -504,7 +510,8 @@
"format": "prettier --write .",
"format:check": "prettier --check .",
"lint": "eslint src",
"test": "vscode-test"
"test": "vscode-test",
"test:unit": "bun test tests/unit/"
},
"devDependencies": {
"@types/diff": "^6.0.0",
@@ -530,6 +537,7 @@
"@kilocode/kilo-ui": "workspace:*",
"@kilocode/sdk": "workspace:*",
"@opencode-ai/ui": "workspace:*",
"@thisbeyond/solid-dnd": "0.7.5",
"diff": "^7.0.0",
"dotenv": "^16.4.7",
"eventsource": "^2.0.2",
+5 -4
View File
@@ -22,7 +22,8 @@ const packagesDir = join(kiloVscodeDir, "..")
const opencodeDir = join(packagesDir, "opencode")
const targetBinDir = join(kiloVscodeDir, "bin")
const targetBinPath = join(targetBinDir, "kilo")
const binName = process.platform === "win32" ? "kilo.exe" : "kilo"
const targetBinPath = join(targetBinDir, binName)
function log(msg: string) {
console.log(`[local-bin] ${msg}`)
@@ -44,7 +45,7 @@ async function findKiloBinaryInOpencodeDist(): Promise<string | null> {
// Prefer the binary matching the current platform (e.g. cli-darwin-arm64)
const tag = platformTag()
const preferred = join(distDir, `@kilocode`, tag, "bin", "kilo")
const preferred = join(distDir, `@kilocode`, tag, "bin", binName)
try {
statSync(preferred)
return preferred
@@ -52,7 +53,7 @@ async function findKiloBinaryInOpencodeDist(): Promise<string | null> {
// fall through to generic search
}
// Fallback: find any dist/**/bin/kilo
// Fallback: find any dist/**/bin/kilo or kilo.exe
const queue = [distDir]
while (queue.length) {
const dir = queue.pop()
@@ -71,7 +72,7 @@ async function findKiloBinaryInOpencodeDist(): Promise<string | null> {
queue.push(p)
continue
}
if (e.isFile() && e.name === "kilo" && basename(dirname(p)) === "bin") {
if (e.isFile() && (e.name === "kilo" || e.name === "kilo.exe") && basename(dirname(p)) === "bin") {
return p
}
}
+151 -144
View File
@@ -1,10 +1,23 @@
import * as vscode from "vscode"
import { z } from "zod"
import { type HttpClient, type SessionInfo, type SSEEvent, type KiloConnectionService } from "./services/cli-backend"
import {
type HttpClient,
type SessionInfo,
type SSEEvent,
type KiloConnectionService,
type KilocodeNotification,
} from "./services/cli-backend"
import { handleChatCompletionRequest } from "./services/autocomplete/chat-autocomplete/handleChatCompletionRequest"
import { handleChatCompletionAccepted } from "./services/autocomplete/chat-autocomplete/handleChatCompletionAccepted"
import { buildWebviewHtml } from "./utils"
import { TelemetryProxy, type TelemetryPropertiesProvider } from "./services/telemetry"
import {
sessionToWebview,
normalizeProviders,
filterVisibleAgents,
buildSettingPath,
mapSSEEventToWebviewMessage,
} from "./kilo-provider-utils"
export class KiloProvider implements vscode.WebviewViewProvider, TelemetryPropertiesProvider {
public static readonly viewType = "kilo-code.new.sidebarView"
@@ -22,12 +35,17 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
private cachedAgentsMessage: unknown = null
/** Cached configLoaded payload so requestConfig can be served before httpClient is ready */
private cachedConfigMessage: unknown = null
/** Cached notificationsLoaded payload */
private cachedNotificationsMessage: unknown = null
private trackedSessionIds: Set<string> = new Set()
/** Per-session directory overrides (e.g., worktree paths registered by AgentManagerProvider). */
private sessionDirectories = new Map<string, string>()
/** Abort controller for the current loadMessages request; aborted when a new session is selected. */
private loadMessagesAbort: AbortController | null = null
private unsubscribeEvent: (() => void) | null = null
private unsubscribeState: (() => void) | null = null
private unsubscribeNotificationDismiss: (() => void) | null = null
private webviewMessageDisposable: vscode.Disposable | null = null
/** Optional interceptor called before the standard message handler.
@@ -37,6 +55,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
constructor(
private readonly extensionUri: vscode.Uri,
private readonly connectionService: KiloConnectionService,
private readonly extensionContext?: vscode.ExtensionContext,
) {
TelemetryProxy.getInstance().setProvider(this)
}
@@ -267,6 +286,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
message.providerID,
message.modelID,
message.agent,
message.variant,
files,
)
break
@@ -285,7 +305,9 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
this.trackedSessionIds.clear()
break
case "loadMessages":
await this.handleLoadMessages(message.sessionID)
// Don't await: allow parallel loads so rapid session switching
// isn't blocked by slow responses for earlier sessions.
void this.handleLoadMessages(message.sessionID)
break
case "syncSession":
await this.handleSyncSession(message.sessionID)
@@ -316,6 +338,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
vscode.env.openExternal(vscode.Uri.parse(message.url))
}
break
case "openFile":
if (message.filePath) {
this.handleOpenFile(message.filePath, message.line, message.column)
}
break
case "requestProviders":
await this.fetchAndSendProviders()
break
@@ -402,12 +429,29 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
case "requestNotificationSettings":
this.sendNotificationSettings()
break
case "requestNotifications":
await this.fetchAndSendNotifications()
break
case "dismissNotification":
await this.handleDismissNotification(message.notificationId)
break
case "resetAllSettings":
await this.handleResetAllSettings()
break
case "telemetry":
TelemetryProxy.capture(message.event, message.properties)
break
case "persistVariant": {
const stored = this.extensionContext?.globalState.get<Record<string, string>>("variantSelections") ?? {}
stored[message.key] = message.value
await this.extensionContext?.globalState.update("variantSelections", stored)
break
}
case "requestVariants": {
const variants = this.extensionContext?.globalState.get<Record<string, string>>("variantSelections") ?? {}
this.postMessage({ type: "variantsLoaded", variants })
break
}
}
})
}
@@ -422,6 +466,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
// Clean up any existing subscriptions (e.g., sidebar re-shown)
this.unsubscribeEvent?.()
this.unsubscribeState?.()
this.unsubscribeNotificationDismiss?.()
try {
const workspaceDir = this.getWorkspaceDirectory()
@@ -469,6 +514,11 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
})
// Subscribe to notification dismiss broadcast from other KiloProvider instances
this.unsubscribeNotificationDismiss = this.connectionService.onNotificationDismissed(() => {
this.fetchAndSendNotifications()
})
// Get current state and push to webview
const serverInfo = this.connectionService.getServerInfo()
this.connectionState = this.connectionService.getConnectionState()
@@ -491,6 +541,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
await this.fetchAndSendProviders()
await this.fetchAndSendAgents()
await this.fetchAndSendConfig()
await this.fetchAndSendNotifications()
this.sendNotificationSettings()
console.log("[Kilo New] KiloProvider: ✅ initializeConnection completed successfully")
@@ -505,16 +556,8 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
}
/**
* Convert SessionInfo to webview format.
*/
private sessionToWebview(session: SessionInfo) {
return {
id: session.id,
title: session.title,
createdAt: new Date(session.time.created).toISOString(),
updatedAt: new Date(session.time.updated).toISOString(),
}
return sessionToWebview(session)
}
/**
@@ -560,25 +603,36 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
this.postMessage({
type: "error",
message: "Not connected to CLI backend",
sessionID,
})
return
}
// Abort any previous in-flight loadMessages request so the backend
// isn't overwhelmed when the user switches sessions rapidly.
this.loadMessagesAbort?.abort()
const abort = new AbortController()
this.loadMessagesAbort = abort
try {
const workspaceDir = this.getWorkspaceDirectory(sessionID)
const messagesData = await this.httpClient.getMessages(sessionID, workspaceDir)
const messagesData = await this.httpClient.getMessages(sessionID, workspaceDir, abort.signal)
// If this request was aborted while awaiting, skip posting stale results
if (abort.signal.aborted) return
// Update currentSession so fallback logic in handleSendMessage/handleAbort
// references the correct session after switching to a historical session.
// Non-blocking: don't let a failure here prevent messages from loading.
// 404s are expected for cross-worktree sessions — use silent to suppress HTTP error logs.
this.httpClient
.getSession(sessionID, workspaceDir)
.getSession(sessionID, workspaceDir, true)
.then((session) => {
if (!this.currentSession || this.currentSession.id === sessionID) {
this.currentSession = session
}
})
.catch((err) => console.error("[Kilo New] KiloProvider: Failed to fetch session for tracking:", err))
.catch((err) => console.warn("[Kilo New] KiloProvider: getSession failed (non-critical):", err))
// Fetch current session status so the webview has the correct busy/idle
// state after switching tabs (SSE events may have been missed).
@@ -618,10 +672,13 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
messages,
})
} catch (error) {
// Silently ignore aborted requests — the user switched to a different session
if (abort.signal.aborted) return
console.error("[Kilo New] KiloProvider: Failed to load messages:", error)
this.postMessage({
type: "error",
message: error instanceof Error ? error.message : "Failed to load messages",
sessionID,
})
}
}
@@ -786,11 +843,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
const workspaceDir = this.getWorkspaceDirectory()
const response = await this.httpClient.listProviders(workspaceDir)
// Re-key providers from numeric indices to provider.id
const normalized: typeof response.all = {}
for (const provider of Object.values(response.all)) {
normalized[provider.id] = provider
}
const normalized = normalizeProviders(response.all)
const config = vscode.workspace.getConfiguration("kilo-code.new.model")
const providerID = config.get<string>("providerID", "kilo")
@@ -825,11 +878,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
const workspaceDir = this.getWorkspaceDirectory()
const agents = await this.httpClient.listAgents(workspaceDir)
// Filter to only visible primary/all modes (not subagents, not hidden)
const visible = agents.filter((a) => a.mode !== "subagent" && !a.hidden)
// Find default agent: first one in list (CLI sorts default first)
const defaultAgent = visible.length > 0 ? visible[0].name : "code"
const { visible, defaultAgent } = filterVisibleAgents(agents)
const message = {
type: "agentsLoaded",
@@ -875,6 +924,47 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
}
/**
* Fetch Kilo news/notifications and send to webview.
* Uses the cached message pattern so the webview gets data immediately on refresh.
*/
private async fetchAndSendNotifications(): Promise<void> {
if (!this.httpClient) {
if (this.cachedNotificationsMessage) {
this.postMessage(this.cachedNotificationsMessage)
}
return
}
try {
const notifications = await this.httpClient.getNotifications()
const existing = this.extensionContext?.globalState.get<string[]>("kilo.dismissedNotificationIds", []) ?? []
const active = new Set(notifications.map((n) => n.id))
const dismissedIds = existing.filter((id) => active.has(id))
if (dismissedIds.length !== existing.length) {
await this.extensionContext?.globalState.update("kilo.dismissedNotificationIds", dismissedIds)
}
const message = { type: "notificationsLoaded", notifications, dismissedIds }
this.cachedNotificationsMessage = message
this.postMessage(message)
} catch (error) {
console.error("[Kilo New] KiloProvider: Failed to fetch notifications:", error)
}
}
/**
* Persist a dismissed notification ID in globalState and push updated lists to webview.
*/
private async handleDismissNotification(notificationId: string): Promise<void> {
if (!this.extensionContext) return
const existing = this.extensionContext.globalState.get<string[]>("kilo.dismissedNotificationIds", [])
if (!existing.includes(notificationId)) {
await this.extensionContext.globalState.update("kilo.dismissedNotificationIds", [...existing, notificationId])
}
await this.fetchAndSendNotifications()
this.connectionService.notifyNotificationDismissed(notificationId)
}
/**
* Read notification/sound settings from VS Code config and push to webview.
*/
@@ -932,6 +1022,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
providerID?: string,
modelID?: string,
agent?: string,
variant?: string,
files?: Array<{ mime: string; url: string }>,
): Promise<void> {
if (!this.httpClient) {
@@ -987,6 +1078,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
providerID,
modelID,
agent,
variant,
})
} catch (error) {
console.error("[Kilo New] KiloProvider: Failed to send message:", error)
@@ -1218,6 +1310,28 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
}
/**
* Handle openFile request from the webview — open a file in the VS Code editor.
*/
private handleOpenFile(filePath: string, line?: number, column?: number): void {
const absolute = /^(?:\/|[a-zA-Z]:[\\/])/.test(filePath)
const uri = absolute
? vscode.Uri.file(filePath)
: vscode.Uri.joinPath(vscode.Uri.file(this.getWorkspaceDirectory()), filePath)
vscode.workspace.openTextDocument(uri).then(
(doc) => {
const options: vscode.TextDocumentShowOptions = { preview: true }
if (line !== undefined && line > 0) {
const col = column !== undefined && column > 0 ? column - 1 : 0
const pos = new vscode.Position(line - 1, col)
options.selection = new vscode.Range(pos, pos)
}
vscode.window.showTextDocument(doc, options)
},
(err) => console.error("[Kilo New] KiloProvider: Failed to open file:", uri.fsPath, err),
)
}
/**
* Handle logout request from the webview.
*/
@@ -1256,9 +1370,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
* The key uses dot notation relative to `kilo-code.new` (e.g. "browserAutomation.enabled").
*/
private async handleUpdateSetting(key: string, value: unknown): Promise<void> {
const parts = key.split(".")
const section = parts.slice(0, -1).join(".")
const leaf = parts[parts.length - 1]
const { section, leaf } = buildSettingPath(key)
const config = vscode.workspace.getConfiguration(`kilo-code.new${section ? `.${section}` : ""}`)
await config.update(leaf, value, vscode.ConfigurationTarget.Global)
}
@@ -1342,124 +1454,18 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
}
// Forward relevant events to webview
switch (event.type) {
case "message.part.updated": {
// The part contains the full part data including messageID, delta is optional text delta
const part = event.properties.part as { messageID?: string; sessionID?: string }
const messageID = part.messageID || ""
// Side effects that must happen before the webview message is sent
if (event.type === "session.created" && !this.currentSession) {
this.currentSession = event.properties.info
this.trackedSessionIds.add(event.properties.info.id)
}
if (event.type === "session.updated" && this.currentSession?.id === event.properties.info.id) {
this.currentSession = event.properties.info
}
const resolvedSessionID = sessionID
if (!resolvedSessionID) {
return
}
this.postMessage({
type: "partUpdated",
sessionID: resolvedSessionID,
messageID,
part: event.properties.part,
delta: event.properties.delta ? { type: "text-delta", textDelta: event.properties.delta } : undefined,
})
break
}
case "message.updated":
// Message info updated — forward cost/tokens for assistant messages
this.postMessage({
type: "messageCreated",
message: {
id: event.properties.info.id,
sessionID: event.properties.info.sessionID,
role: event.properties.info.role,
createdAt: new Date(event.properties.info.time.created).toISOString(),
cost: event.properties.info.cost,
tokens: event.properties.info.tokens,
},
})
break
case "session.status": {
const info = event.properties.status
this.postMessage({
type: "sessionStatus",
sessionID: event.properties.sessionID,
status: info.type,
...(info.type === "retry" ? { attempt: info.attempt, message: info.message, next: info.next } : {}),
})
break
}
case "permission.asked":
this.postMessage({
type: "permissionRequest",
permission: {
id: event.properties.id,
sessionID: event.properties.sessionID,
toolName: event.properties.permission,
patterns: event.properties.patterns ?? [],
args: event.properties.metadata,
message: `Permission required: ${event.properties.permission}`,
tool: event.properties.tool,
},
})
break
case "todo.updated":
this.postMessage({
type: "todoUpdated",
sessionID: event.properties.sessionID,
items: event.properties.items,
})
break
case "question.asked":
this.postMessage({
type: "questionRequest",
question: {
id: event.properties.id,
sessionID: event.properties.sessionID,
questions: event.properties.questions,
tool: event.properties.tool,
},
})
break
case "question.replied":
this.postMessage({
type: "questionResolved",
requestID: event.properties.requestID,
})
break
case "question.rejected":
this.postMessage({
type: "questionResolved",
requestID: event.properties.requestID,
})
break
case "session.created":
// Store session if we don't have one yet
if (!this.currentSession) {
this.currentSession = event.properties.info
this.trackedSessionIds.add(event.properties.info.id)
}
// Notify webview
this.postMessage({
type: "sessionCreated",
session: this.sessionToWebview(event.properties.info),
})
break
case "session.updated":
// Keep local state in sync (e.g. title generation)
if (this.currentSession?.id === event.properties.info.id) {
this.currentSession = event.properties.info
}
this.postMessage({
type: "sessionUpdated",
session: this.sessionToWebview(event.properties.info),
})
break
const msg = mapSSEEventToWebviewMessage(event, sessionID)
if (msg) {
this.postMessage(msg)
}
}
@@ -1534,6 +1540,7 @@ export class KiloProvider implements vscode.WebviewViewProvider, TelemetryProper
dispose(): void {
this.unsubscribeEvent?.()
this.unsubscribeState?.()
this.unsubscribeNotificationDismiss?.()
this.webviewMessageDisposable?.dispose()
this.trackedSessionIds.clear()
this.sessionDirectories.clear()
@@ -4,7 +4,10 @@ import { KiloProvider } from "../KiloProvider"
import { buildWebviewHtml } from "../utils"
import { WorktreeManager, type CreateWorktreeResult } from "./WorktreeManager"
import { WorktreeStateManager } from "./WorktreeStateManager"
import { SetupScriptService } from "./SetupScriptService"
import { SetupScriptRunner } from "./SetupScriptRunner"
import { SessionTerminalManager } from "./SessionTerminalManager"
import { formatKeybinding } from "./format-keybinding"
/**
* AgentManagerProvider opens the Agent Manager panel.
@@ -22,7 +25,9 @@ export class AgentManagerProvider implements vscode.Disposable {
private outputChannel: vscode.OutputChannel
private worktrees: WorktreeManager | undefined
private state: WorktreeStateManager | undefined
private setupScript: SetupScriptService | undefined
private terminalManager: SessionTerminalManager
private stateReady: Promise<void> | undefined
constructor(
private readonly extensionUri: vscode.Uri,
@@ -70,8 +75,9 @@ export class AgentManagerProvider implements vscode.Disposable {
onBeforeMessage: (msg) => this.onMessage(msg),
})
void this.initializeState()
this.stateReady = this.initializeState()
void this.sendRepoInfo()
this.sendKeybindings()
this.panel.onDidDispose(() => {
this.log("Panel disposed")
@@ -88,7 +94,10 @@ export class AgentManagerProvider implements vscode.Disposable {
private async initializeState(): Promise<void> {
const manager = this.getWorktreeManager()
const state = this.getStateManager()
if (!manager || !state) return
if (!manager || !state) {
this.pushEmptyState()
return
}
await state.load()
@@ -129,6 +138,10 @@ export class AgentManagerProvider implements vscode.Disposable {
return this.onAddSessionToWorktree(msg.worktreeId)
if (type === "agentManager.closeSession" && typeof msg.sessionId === "string")
return this.onCloseSession(msg.sessionId)
if (type === "agentManager.configureSetupScript") {
void this.configureSetupScript()
return null
}
if (type === "agentManager.showTerminal" && typeof msg.sessionId === "string") {
this.terminalManager.showTerminal(msg.sessionId, this.state)
return null
@@ -137,6 +150,37 @@ export class AgentManagerProvider implements vscode.Disposable {
void this.sendRepoInfo()
return null
}
if (type === "agentManager.createMultiVersion") {
void this.onCreateMultiVersion(msg)
return null
}
if (type === "agentManager.requestState") {
void this.stateReady
?.then(() => {
this.pushState()
// Refresh sessions after pushState so the webview's sessionsLoaded
// handler is guaranteed to be registered (requestState fires from
// onMount). Without this, the initial refreshSessions() in
// initializeState() can race ahead of webview mount, causing
// sessionsLoaded to never flip to true.
if (this.state && this.state.getSessions().length > 0) {
this.provider?.refreshSessions()
}
})
.catch((err) => {
this.log("initializeState failed, pushing partial state:", err)
this.pushState()
})
return null
}
if (type === "agentManager.setTabOrder" && typeof msg.key === "string" && Array.isArray(msg.order)) {
this.state?.setTabOrder(msg.key as string, msg.order as string[])
return null
}
if (type === "agentManager.setSessionsCollapsed" && typeof msg.collapsed === "boolean") {
this.state?.setSessionsCollapsed(msg.collapsed as boolean)
return null
}
// When switching sessions, show existing terminal if one is open
if (type === "loadMessages" && typeof msg.sessionID === "string") {
@@ -161,14 +205,18 @@ export class AgentManagerProvider implements vscode.Disposable {
// ---------------------------------------------------------------------------
/** Create a git worktree on disk and register it in state. Returns null on failure. */
private async createWorktreeOnDisk(): Promise<{
private async createWorktreeOnDisk(groupId?: string): Promise<{
worktree: ReturnType<WorktreeStateManager["addWorktree"]>
result: CreateWorktreeResult
} | null> {
const manager = this.getWorktreeManager()
const state = this.getStateManager()
if (!manager || !state) {
this.postToWebview({ type: "agentManager.worktreeSetup", status: "error", message: "No workspace folder open" })
this.postToWebview({
type: "agentManager.worktreeSetup",
status: "error",
message: "Open a folder that contains a git repository to use worktrees",
})
return null
}
@@ -178,21 +226,41 @@ export class AgentManagerProvider implements vscode.Disposable {
try {
result = await manager.createWorktree({ prompt: "kilo" })
} catch (error) {
const err = error instanceof Error ? error.message : String(error)
const msg = error instanceof Error ? error.message : String(error)
this.postToWebview({
type: "agentManager.worktreeSetup",
status: "error",
message: `Failed to create worktree: ${err}`,
message: msg,
})
return null
}
const worktree = state.addWorktree({ branch: result.branch, path: result.path, parentBranch: result.parentBranch })
const worktree = state.addWorktree({
branch: result.branch,
path: result.path,
parentBranch: result.parentBranch,
groupId,
})
// Push state immediately so the sidebar shows the new worktree with a loading indicator
this.pushState()
this.postToWebview({
type: "agentManager.worktreeSetup",
status: "creating",
message: "Setting up workspace...",
branch: result.branch,
worktreeId: worktree.id,
})
return { worktree, result }
}
/** Create a CLI session in a worktree directory. Returns null on failure. */
private async createSessionInWorktree(worktreePath: string, branch: string): Promise<SessionInfo | null> {
private async createSessionInWorktree(
worktreePath: string,
branch: string,
worktreeId?: string,
): Promise<SessionInfo | null> {
let client: HttpClient
try {
client = this.connectionService.getHttpClient()
@@ -201,6 +269,7 @@ export class AgentManagerProvider implements vscode.Disposable {
type: "agentManager.worktreeSetup",
status: "error",
message: "Not connected to CLI backend",
worktreeId,
})
return null
}
@@ -210,6 +279,7 @@ export class AgentManagerProvider implements vscode.Disposable {
status: "starting",
message: "Starting session...",
branch,
worktreeId,
})
try {
@@ -220,13 +290,14 @@ export class AgentManagerProvider implements vscode.Disposable {
type: "agentManager.worktreeSetup",
status: "error",
message: `Failed to create session: ${err}`,
worktreeId,
})
return null
}
}
/** Send worktreeSetup.ready + sessionMeta + pushState after worktree creation. */
private notifyWorktreeReady(sessionId: string, result: CreateWorktreeResult): void {
private notifyWorktreeReady(sessionId: string, result: CreateWorktreeResult, worktreeId?: string): void {
this.pushState()
this.postToWebview({
type: "agentManager.worktreeSetup",
@@ -234,6 +305,7 @@ export class AgentManagerProvider implements vscode.Disposable {
message: "Worktree ready",
sessionId,
branch: result.branch,
worktreeId,
})
this.postToWebview({
type: "agentManager.sessionMeta",
@@ -254,19 +326,23 @@ export class AgentManagerProvider implements vscode.Disposable {
const created = await this.createWorktreeOnDisk()
if (!created) return null
const session = await this.createSessionInWorktree(created.result.path, created.result.branch)
// Run setup script for new worktree (blocks until complete, shows in overlay)
await this.runSetupScriptForWorktree(created.result.path, created.result.branch, created.worktree.id)
const session = await this.createSessionInWorktree(created.result.path, created.result.branch, created.worktree.id)
if (!session) {
const state = this.getStateManager()
const manager = this.getWorktreeManager()
state?.removeWorktree(created.worktree.id)
await manager?.removeWorktree(created.result.path)
this.pushState()
return null
}
const state = this.getStateManager()!
state.addSession(session.id, created.worktree.id)
this.registerWorktreeSession(session.id, created.result.path)
this.notifyWorktreeReady(session.id, created.result)
this.notifyWorktreeReady(session.id, created.result, created.worktree.id)
this.log(`Created worktree ${created.worktree.id} with session ${session.id}`)
return null
}
@@ -303,6 +379,9 @@ export class AgentManagerProvider implements vscode.Disposable {
const created = await this.createWorktreeOnDisk()
if (!created) return null
// Run setup script for new worktree (blocks until complete, shows in overlay)
await this.runSetupScriptForWorktree(created.result.path, created.result.branch, created.worktree.id)
const state = this.getStateManager()!
if (!state.getSession(sessionId)) {
state.addSession(sessionId, created.worktree.id)
@@ -311,7 +390,7 @@ export class AgentManagerProvider implements vscode.Disposable {
}
this.registerWorktreeSession(sessionId, created.result.path)
this.notifyWorktreeReady(sessionId, created.result)
this.notifyWorktreeReady(sessionId, created.result, created.worktree.id)
this.log(`Promoted session ${sessionId} to worktree ${created.worktree.id}`)
return null
}
@@ -372,6 +451,210 @@ export class AgentManagerProvider implements vscode.Disposable {
return null
}
// ---------------------------------------------------------------------------
// Multi-version worktree creation
// ---------------------------------------------------------------------------
/** Create N worktree sessions for the same prompt (multi-version mode). */
private async onCreateMultiVersion(msg: Record<string, unknown>): Promise<null> {
const text = msg.text as string
if (!text) return null
const versions = Math.min(Math.max(Number(msg.versions) || 1, 1), 4)
const providerID = msg.providerID as string | undefined
const modelID = msg.modelID as string | undefined
const agent = msg.agent as string | undefined
const files = msg.files as Array<{ mime: string; url: string }> | undefined
// Generate a shared group ID for multi-version worktrees
const groupId = versions > 1 ? `grp-${Date.now()}` : undefined
this.log(
`Creating ${versions} multi-version worktrees for: ${text.slice(0, 60)}${groupId ? ` (group=${groupId})` : ""}`,
)
// Notify webview that multi-version creation has started
this.postToWebview({
type: "agentManager.multiVersionProgress",
status: "creating",
total: versions,
completed: 0,
groupId,
})
// Phase 1: Create all worktrees + sessions first
const created: Array<{
worktreeId: string
sessionId: string
path: string
branch: string
parentBranch: string
}> = []
for (let i = 0; i < versions; i++) {
this.log(`Creating worktree ${i + 1}/${versions}`)
const wt = await this.createWorktreeOnDisk(groupId)
if (!wt) {
this.log(`Failed to create worktree for version ${i + 1}`)
continue
}
await this.runSetupScriptForWorktree(wt.result.path, wt.result.branch)
const session = await this.createSessionInWorktree(wt.result.path, wt.result.branch)
if (!session) {
const state = this.getStateManager()
const manager = this.getWorktreeManager()
state?.removeWorktree(wt.worktree.id)
await manager?.removeWorktree(wt.result.path)
this.log(`Failed to create session for version ${i + 1}`)
continue
}
const state = this.getStateManager()!
state.addSession(session.id, wt.worktree.id)
this.registerWorktreeSession(session.id, wt.result.path)
this.notifyWorktreeReady(session.id, wt.result)
created.push({
worktreeId: wt.worktree.id,
sessionId: session.id,
path: wt.result.path,
branch: wt.result.branch,
parentBranch: wt.result.parentBranch,
})
this.log(`Version ${i + 1} worktree ready: session=${session.id}`)
// Update progress
this.postToWebview({
type: "agentManager.multiVersionProgress",
status: "creating",
total: versions,
completed: created.length,
groupId,
})
}
// Phase 2: Send the initial prompt to all sessions via the KiloProvider's
// message handling (same path as typing in the chat). This ensures SSE
// subscriptions and session tracking are properly set up before the message
// is sent. We route each message through the webview→KiloProvider pipeline.
for (let i = 0; i < created.length; i++) {
const entry = created[i]!
this.log(`Sending initial message to version ${i + 1} (session=${entry.sessionId})`)
// Tell the webview to send the message through the normal session flow
this.postToWebview({
type: "agentManager.sendInitialMessage",
sessionId: entry.sessionId,
worktreeId: entry.worktreeId,
text,
providerID,
modelID,
agent,
files,
})
// Small delay between sends to avoid overwhelming the backend
if (i < created.length - 1) {
await new Promise((resolve) => setTimeout(resolve, 300))
}
}
// Notify completion
this.postToWebview({
type: "agentManager.multiVersionProgress",
status: "done",
total: versions,
completed: created.length,
groupId,
})
if (created.length === 0) {
vscode.window.showErrorMessage(`Failed to create any of the ${versions} multi-version worktrees.`)
}
this.log(`Multi-version creation complete: ${created.length}/${versions} versions`)
return null
}
// ---------------------------------------------------------------------------
// Keybindings
// ---------------------------------------------------------------------------
private sendKeybindings(): void {
const ext = vscode.extensions.getExtension("kilocode.kilo-code")
const keybindings: Array<{ command: string; key?: string; mac?: string }> =
ext?.packageJSON?.contributes?.keybindings ?? []
const mac = process.platform === "darwin"
const prefix = "kilo-code.new.agentManager."
const bindings: Record<string, string> = {}
// Global keybindings exposed to the shortcuts dialog
const globals: Record<string, string> = {
"kilo-code.new.agentManagerOpen": "agentManagerOpen",
}
for (const kb of keybindings) {
const raw = mac ? (kb.mac ?? kb.key) : kb.key
if (!raw) continue
if (kb.command.startsWith(prefix)) {
bindings[kb.command.slice(prefix.length)] = formatKeybinding(raw, mac)
} else if (globals[kb.command]) {
bindings[globals[kb.command]] = formatKeybinding(raw, mac)
}
}
this.postToWebview({ type: "agentManager.keybindings", bindings })
}
// ---------------------------------------------------------------------------
// Setup script
// ---------------------------------------------------------------------------
/** Open the worktree setup script in the editor for user configuration. */
private async configureSetupScript(): Promise<void> {
const service = this.getSetupScriptService()
if (!service) return
try {
await service.openInEditor()
} catch (error) {
this.log(`Failed to open setup script: ${error}`)
}
}
/** Run the worktree setup script if configured. Blocks until complete. Shows progress in overlay. */
private async runSetupScriptForWorktree(worktreePath: string, branch?: string, worktreeId?: string): Promise<void> {
const root = this.getWorkspaceRoot()
if (!root) return
try {
const service = this.getSetupScriptService()
if (!service || !service.hasScript()) return
this.postToWebview({
type: "agentManager.worktreeSetup",
status: "creating",
message: "Running setup script...",
branch,
worktreeId,
})
const runner = new SetupScriptRunner(this.outputChannel, service)
await runner.runIfConfigured({ worktreePath, repoPath: root })
} catch (error) {
const msg = error instanceof Error ? error.message : String(error)
this.outputChannel.appendLine(`[AgentManager] Setup script error: ${msg}`)
this.postToWebview({
type: "agentManager.worktreeSetup",
status: "error",
message: `Setup script failed: ${msg}`,
branch,
})
}
}
// ---------------------------------------------------------------------------
// Repo info
// ---------------------------------------------------------------------------
@@ -404,6 +687,19 @@ export class AgentManagerProvider implements vscode.Disposable {
type: "agentManager.state",
worktrees: state.getWorktrees(),
sessions: state.getSessions(),
tabOrder: state.getTabOrder(),
sessionsCollapsed: state.getSessionsCollapsed(),
isGitRepo: true,
})
}
/** Push empty state when the workspace is not a git repo or has no workspace folder. */
private pushEmptyState(): void {
this.postToWebview({
type: "agentManager.state",
worktrees: [],
sessions: [],
isGitRepo: false,
})
}
@@ -439,6 +735,17 @@ export class AgentManagerProvider implements vscode.Disposable {
return this.state
}
private getSetupScriptService(): SetupScriptService | undefined {
if (this.setupScript) return this.setupScript
const root = this.getWorkspaceRoot()
if (!root) {
this.log("getSetupScriptService: no workspace folder available")
return undefined
}
this.setupScript = new SetupScriptService(root)
return this.setupScript
}
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
@@ -474,6 +781,10 @@ export class AgentManagerProvider implements vscode.Disposable {
this.panel.reveal(vscode.ViewColumn.One, false)
}
public isActive(): boolean {
return this.panel?.active === true
}
public postMessage(message: unknown): void {
this.panel?.webview.postMessage(message)
}
@@ -42,7 +42,7 @@ export class SessionTerminalManager {
if (!cwd) {
this.log(`showTerminal: no cwd resolved for session ${sessionId}`)
vscode.window.showWarningMessage("No workspace folder open")
vscode.window.showWarningMessage("Open a folder that contains a git repository to use worktrees")
return
}
@@ -0,0 +1,152 @@
/**
* SetupScriptRunner - Executes worktree setup scripts
*
* Runs setup scripts in VS Code integrated terminal before agent starts.
* Uses VS Code shell integration to track execution and exit code.
* Falls back to sendText + onDidCloseTerminal if shell integration is unavailable.
* Cross-platform: Unix uses sh, Windows uses cmd.exe.
*/
import * as vscode from "vscode"
import { SetupScriptService } from "./SetupScriptService"
import { buildSetupCommand } from "./setup-script-command"
export interface SetupScriptEnvironment {
/** Absolute path to the worktree directory */
worktreePath: string
/** Absolute path to the main repository */
repoPath: string
}
export class SetupScriptRunner {
constructor(
private readonly output: vscode.OutputChannel,
private readonly service: SetupScriptService,
) {}
/**
* Execute setup script in a worktree if script exists.
* Waits for the script to finish before resolving.
*
* @returns true if script was executed, false if skipped (no script configured)
*/
async runIfConfigured(env: SetupScriptEnvironment): Promise<boolean> {
if (!this.service.hasScript()) {
this.log("No setup script configured, skipping")
return false
}
const script = this.service.getScriptPath()
this.log(`Running setup script: ${script}`)
try {
await this.executeInTerminal(script, env)
this.log("Setup script completed")
return true
} catch (error) {
const msg = error instanceof Error ? error.message : String(error)
this.log(`Setup script execution failed: ${msg}`)
return true // Script was attempted
}
}
/** Execute the setup script in a VS Code terminal and wait for it to finish. */
private async executeInTerminal(script: string, env: SetupScriptEnvironment): Promise<void> {
const terminal = vscode.window.createTerminal({
name: "Worktree Setup",
cwd: env.worktreePath,
env: {
WORKTREE_PATH: env.worktreePath,
REPO_PATH: env.repoPath,
},
iconPath: new vscode.ThemeIcon("gear"),
})
terminal.show(true)
// Try shell integration first — gives us proper exit code tracking
const integration = await this.waitForShellIntegration(terminal, 5000)
if (integration) {
this.log("Using shell integration for setup script execution")
await this.runViaShellIntegration(terminal, integration, script, env)
} else {
this.log("Shell integration unavailable, falling back to sendText")
await this.runViaSendText(terminal, script, env)
}
}
/** Wait for shell integration to become available on a terminal, with timeout. */
private waitForShellIntegration(
terminal: vscode.Terminal,
timeout: number,
): Promise<vscode.TerminalShellIntegration | undefined> {
if (terminal.shellIntegration) return Promise.resolve(terminal.shellIntegration)
return new Promise((resolve) => {
const timer = setTimeout(() => {
listener.dispose()
resolve(undefined)
}, timeout)
const listener = vscode.window.onDidChangeTerminalShellIntegration((e) => {
if (e.terminal !== terminal) return
clearTimeout(timer)
listener.dispose()
resolve(e.shellIntegration)
})
})
}
/** Run script via shell integration — tracks execution and exit code properly. */
private runViaShellIntegration(
terminal: vscode.Terminal,
integration: vscode.TerminalShellIntegration,
script: string,
env: SetupScriptEnvironment,
): Promise<void> {
return new Promise((resolve) => {
const command = buildSetupCommand(script, env)
const execution = integration.executeCommand(command)
const cleanup = () => {
execListener.dispose()
closeListener.dispose()
}
// Primary: shell integration reports execution finished with exit code
const execListener = vscode.window.onDidEndTerminalShellExecution((e) => {
if (e.execution !== execution) return
cleanup()
this.log(`Setup script exited with code ${e.exitCode ?? "unknown"}`)
resolve()
})
// Fallback: terminal was closed externally (user, VS Code restart, etc.)
const closeListener = vscode.window.onDidCloseTerminal((closed) => {
if (closed !== terminal) return
cleanup()
this.log("Setup script terminal closed before execution event fired")
resolve()
})
})
}
/** Fallback: run via sendText and wait for terminal to close. */
private runViaSendText(terminal: vscode.Terminal, script: string, env: SetupScriptEnvironment): Promise<void> {
return new Promise((resolve) => {
const listener = vscode.window.onDidCloseTerminal((closed) => {
if (closed !== terminal) return
listener.dispose()
resolve()
})
const command = buildSetupCommand(script, env) + (process.platform === "win32" ? "& exit" : "; exit")
terminal.sendText(command)
this.log("Setup script started in terminal, waiting for completion...")
})
}
private log(message: string): void {
this.output.appendLine(`[SetupScriptRunner] ${message}`)
}
}
@@ -0,0 +1,68 @@
/**
* SetupScriptService - Manages worktree setup scripts
*
* Handles reading, creating, and checking for setup scripts stored in .kilocode/setup-script.
* Setup scripts run before an agent starts in a worktree (new sessions only).
*/
import * as vscode from "vscode"
import * as fs from "node:fs"
import * as path from "node:path"
import { SETUP_SCRIPT_TEMPLATE } from "./setup-script-template"
const SETUP_SCRIPT_FILENAME = "setup-script"
const KILOCODE_DIR = ".kilocode"
export class SetupScriptService {
private readonly root: string
private readonly script: string
constructor(root: string) {
this.root = root
this.script = path.join(root, KILOCODE_DIR, SETUP_SCRIPT_FILENAME)
}
/** Get the path to the setup script */
getScriptPath(): string {
return this.script
}
/** Check if a setup script exists */
hasScript(): boolean {
return fs.existsSync(this.script)
}
/** Read the setup script content. Returns null if not found or read fails. */
async getScript(): Promise<string | null> {
if (!this.hasScript()) return null
try {
return await fs.promises.readFile(this.script, "utf-8")
} catch (error) {
this.log(`Failed to read setup script: ${error}`)
return null
}
}
/** Create a default setup script with helpful comments */
async createDefaultScript(): Promise<void> {
const dir = path.join(this.root, KILOCODE_DIR)
if (!fs.existsSync(dir)) {
await fs.promises.mkdir(dir, { recursive: true })
}
await fs.promises.writeFile(this.script, SETUP_SCRIPT_TEMPLATE, "utf-8")
}
/** Open the setup script in VS Code editor. Creates the default script if it doesn't exist. */
async openInEditor(): Promise<void> {
if (!this.hasScript()) {
await this.createDefaultScript()
}
const document = await vscode.workspace.openTextDocument(this.script)
await vscode.window.showTextDocument(document)
}
private log(message: string): void {
// Log to console since we don't have an OutputChannel here
console.log(`[SetupScriptService] ${message}`)
}
}
@@ -46,7 +46,10 @@ export class WorktreeManager {
async createWorktree(params: { prompt?: string; existingBranch?: string }): Promise<CreateWorktreeResult> {
const repo = await this.git.checkIsRepo()
if (!repo) throw new Error("Workspace is not a git repository")
if (!repo)
throw new Error(
"This folder is not a git repository. Initialize a repository or open a git project to use worktrees.",
)
await this.ensureDir()
await this.ensureGitExclude()
@@ -182,6 +185,7 @@ export class WorktreeManager {
const excludePath = path.join(gitDir, "info", "exclude")
await this.addExcludeEntry(excludePath, ".kilocode/worktrees/", "Kilo Code agent worktrees")
await this.addExcludeEntry(excludePath, ".kilocode/agent-manager.json", "Kilo Agent Manager state")
await this.addExcludeEntry(excludePath, ".kilocode/setup-script", "Kilo Code worktree setup script")
}
private async ensureWorktreeExclude(worktreePath: string): Promise<void> {
@@ -18,6 +18,8 @@ export interface Worktree {
path: string
parentBranch: string
createdAt: string
/** Shared identifier for worktrees created together via multi-version mode. */
groupId?: string
}
export interface ManagedSession {
@@ -29,6 +31,8 @@ export interface ManagedSession {
interface StateFile {
worktrees: Record<string, Omit<Worktree, "id">>
sessions: Record<string, Omit<ManagedSession, "id">>
tabOrder?: Record<string, string[]>
sessionsCollapsed?: boolean
}
const STATE_FILE = "agent-manager.json"
@@ -44,6 +48,8 @@ export class WorktreeStateManager {
private readonly file: string
private worktrees = new Map<string, Worktree>()
private sessions = new Map<string, ManagedSession>()
private tabOrder: Record<string, string[]> = {}
private collapsed = false
private readonly log: (msg: string) => void
private saving: Promise<void> | undefined
private pendingSave = false
@@ -103,11 +109,18 @@ export class WorktreeStateManager {
// Mutations
// ---------------------------------------------------------------------------
addWorktree(params: { branch: string; path: string; parentBranch: string }): Worktree {
addWorktree(params: { branch: string; path: string; parentBranch: string; groupId?: string }): Worktree {
const id = generateId("wt")
const wt: Worktree = { id, ...params, createdAt: new Date().toISOString() }
const wt: Worktree = {
id,
branch: params.branch,
path: params.path,
parentBranch: params.parentBranch,
createdAt: new Date().toISOString(),
}
if (params.groupId) wt.groupId = params.groupId
this.worktrees.set(id, wt)
this.log(`Added worktree ${id}: ${params.branch}`)
this.log(`Added worktree ${id}: ${params.branch}${params.groupId ? ` (group=${params.groupId})` : ""}`)
void this.save()
return wt
}
@@ -125,6 +138,9 @@ export class WorktreeStateManager {
}
}
// Clean up tab order for this worktree
delete this.tabOrder[id]
this.log(`Removed worktree ${id}, orphaned ${orphaned.length} sessions`)
void this.save()
return orphaned
@@ -149,6 +165,47 @@ export class WorktreeStateManager {
removeSession(id: string): void {
this.sessions.delete(id)
// Remove this session from any tab order arrays
for (const [key, order] of Object.entries(this.tabOrder)) {
const idx = order.indexOf(id)
if (idx !== -1) {
order.splice(idx, 1)
if (order.length === 0) delete this.tabOrder[key]
}
}
void this.save()
}
// ---------------------------------------------------------------------------
// Tab order
// ---------------------------------------------------------------------------
getTabOrder(): Record<string, string[]> {
return this.tabOrder
}
setTabOrder(key: string, order: string[]): void {
this.tabOrder[key] = order
void this.save()
}
removeTabOrder(key: string): void {
delete this.tabOrder[key]
void this.save()
}
// ---------------------------------------------------------------------------
// Sessions collapsed
// ---------------------------------------------------------------------------
getSessionsCollapsed(): boolean {
return this.collapsed
}
setSessionsCollapsed(value: boolean): void {
this.collapsed = value
void this.save()
}
@@ -162,6 +219,7 @@ export class WorktreeStateManager {
const data = JSON.parse(content) as StateFile
this.worktrees.clear()
this.sessions.clear()
this.tabOrder = {}
for (const [id, wt] of Object.entries(data.worktrees ?? {})) {
this.worktrees.set(id, { id, ...wt })
@@ -169,6 +227,10 @@ export class WorktreeStateManager {
for (const [id, s] of Object.entries(data.sessions ?? {})) {
this.sessions.set(id, { id, ...s })
}
if (data.tabOrder) {
this.tabOrder = data.tabOrder
}
this.collapsed = data.sessionsCollapsed ?? false
this.log(`Loaded state: ${this.worktrees.size} worktrees, ${this.sessions.size} sessions`)
} catch (error) {
const code = (error as NodeJS.ErrnoException).code
@@ -229,6 +291,12 @@ export class WorktreeStateManager {
const { id: _, ...rest } = s
data.sessions[id] = rest
}
if (Object.keys(this.tabOrder).length > 0) {
data.tabOrder = this.tabOrder
}
if (this.collapsed) {
data.sessionsCollapsed = true
}
const dir = path.dirname(this.file)
if (!fs.existsSync(dir)) await fs.promises.mkdir(dir, { recursive: true })
@@ -0,0 +1,85 @@
import { describe, it, expect } from "vitest"
import { buildSetupCommand } from "../setup-script-command"
const env = {
worktreePath: "/repos/project/.kilocode/worktrees/wt-1",
repoPath: "/repos/project",
}
const script = "/repos/project/.kilocode/setup-script"
describe("buildSetupCommand", () => {
it("builds unix command with inline env vars and sh", () => {
const result = buildSetupCommand(script, env, "darwin")
expect(result).toBe(
`WORKTREE_PATH="/repos/project/.kilocode/worktrees/wt-1" REPO_PATH="/repos/project" sh "/repos/project/.kilocode/setup-script"`,
)
})
it("builds linux command same as darwin", () => {
const result = buildSetupCommand(script, env, "linux")
expect(result).toContain("sh ")
expect(result).not.toContain("set ")
expect(result).not.toContain("call ")
})
it("builds windows command with set and call", () => {
const result = buildSetupCommand(script, env, "win32")
expect(result).toBe(
`set "WORKTREE_PATH=/repos/project/.kilocode/worktrees/wt-1" && set "REPO_PATH=/repos/project" && call "/repos/project/.kilocode/setup-script"`,
)
})
it("includes both env vars in unix command", () => {
const result = buildSetupCommand(script, env, "darwin")
expect(result).toContain(`WORKTREE_PATH="${env.worktreePath}"`)
expect(result).toContain(`REPO_PATH="${env.repoPath}"`)
})
it("includes both env vars in windows command", () => {
const result = buildSetupCommand(script, env, "win32")
expect(result).toContain(`set "WORKTREE_PATH=${env.worktreePath}"`)
expect(result).toContain(`set "REPO_PATH=${env.repoPath}"`)
})
it("handles paths with spaces", () => {
const spaced = {
worktreePath: "/Users/dev/my project/.kilocode/worktrees/wt-1",
repoPath: "/Users/dev/my project",
}
const spacedScript = "/Users/dev/my project/.kilocode/setup-script"
const unix = buildSetupCommand(spacedScript, spaced, "darwin")
expect(unix).toContain(`sh "/Users/dev/my project/.kilocode/setup-script"`)
const win = buildSetupCommand(spacedScript, spaced, "win32")
expect(win).toContain(`call "/Users/dev/my project/.kilocode/setup-script"`)
})
it("escapes double quotes in unix paths", () => {
const dangerous = {
worktreePath: '/repos/proj"ect',
repoPath: "/repos/safe",
}
const result = buildSetupCommand(script, dangerous, "darwin")
expect(result).toContain(`WORKTREE_PATH="/repos/proj\\"ect"`)
})
it("escapes dollar signs in unix paths", () => {
const dangerous = {
worktreePath: "/repos/$HOME/project",
repoPath: "/repos/safe",
}
const result = buildSetupCommand(script, dangerous, "darwin")
expect(result).toContain(`WORKTREE_PATH="/repos/\\$HOME/project"`)
})
it("escapes backticks in unix paths", () => {
const dangerous = {
worktreePath: "/repos/`whoami`/project",
repoPath: "/repos/safe",
}
const result = buildSetupCommand(script, dangerous, "darwin")
expect(result).toContain('WORKTREE_PATH="/repos/\\`whoami\\`/project"')
})
})
@@ -0,0 +1,34 @@
const KEY_SYMBOLS: Record<string, { mac: string; other: string }> = {
ctrl: { mac: "⌃", other: "Ctrl" },
cmd: { mac: "⌘", other: "Ctrl" },
shift: { mac: "⇧", other: "Shift" },
alt: { mac: "⌥", other: "Alt" },
}
const SPECIAL_KEYS: Record<string, string> = {
left: "←",
right: "→",
up: "↑",
down: "↓",
backspace: "⌫",
delete: "Del",
enter: "↵",
escape: "Esc",
}
/**
* Format a VS Code keybinding string (e.g. "cmd+shift+w") into
* a display string using platform-appropriate symbols.
* Mac: "⌘⇧W" Windows/Linux: "Ctrl+Shift+W"
*/
export function formatKeybinding(raw: string, mac: boolean): string {
const symbols = raw
.split("+")
.map((p) => p.trim().toLowerCase())
.map((part) => {
const mod = KEY_SYMBOLS[part]
if (mod) return mac ? mod.mac : mod.other
return SPECIAL_KEYS[part] ?? part.toUpperCase()
})
return mac ? symbols.join("") : symbols.join("+")
}
@@ -0,0 +1,21 @@
/** Escape characters that are special inside double-quoted shell strings. */
function escapeShell(value: string): string {
return value.replace(/["$`\\]/g, "\\$&")
}
/** Build the platform-appropriate command string for running a setup script. */
export function buildSetupCommand(
script: string,
env: { worktreePath: string; repoPath: string },
platform: NodeJS.Platform = process.platform,
): string {
if (platform === "win32") {
// Windows cmd.exe: double quotes in set values don't need escaping the same way,
// but we escape for the call argument
return `set "WORKTREE_PATH=${env.worktreePath}" && set "REPO_PATH=${env.repoPath}" && call "${script}"`
}
const wt = escapeShell(env.worktreePath)
const repo = escapeShell(env.repoPath)
const path = escapeShell(script)
return `WORKTREE_PATH="${wt}" REPO_PATH="${repo}" sh "${path}"`
}
@@ -0,0 +1,41 @@
/** Default template for worktree setup scripts. */
export const SETUP_SCRIPT_TEMPLATE = `#!/bin/bash
# Kilo Code Worktree Setup Script
# This script runs before the agent starts in a worktree (new sessions only).
#
# Available environment variables:
# WORKTREE_PATH - Absolute path to the worktree directory
# REPO_PATH - Absolute path to the main repository
#
# Example tasks:
# - Copy .env files from main repo
# - Install dependencies
# - Run database migrations
# - Set up local configuration
set -e # Exit on error
echo "Setting up worktree: $WORKTREE_PATH"
# Uncomment and modify as needed:
# Copy environment files
# if [ -f "$REPO_PATH/.env" ]; then
# cp "$REPO_PATH/.env" "$WORKTREE_PATH/.env"
# echo "Copied .env"
# fi
# Install dependencies (Node.js)
# if [ -f "$WORKTREE_PATH/package.json" ]; then
# cd "$WORKTREE_PATH"
# npm install
# fi
# Install dependencies (Python)
# if [ -f "$WORKTREE_PATH/requirements.txt" ]; then
# cd "$WORKTREE_PATH"
# pip install -r requirements.txt
# fi
echo "Setup complete!"
`
+3 -3
View File
@@ -33,7 +33,7 @@ export function activate(context: vscode.ExtensionContext) {
})
// Create the provider with shared service
const provider = new KiloProvider(context.extensionUri, connectionService)
const provider = new KiloProvider(context.extensionUri, connectionService, context)
// Register the webview view provider for the sidebar.
// retainContextWhenHidden keeps the webview alive when switching to other sidebar panels.
@@ -109,7 +109,7 @@ export function activate(context: vscode.ExtensionContext) {
registerCommitMessageService(context, connectionService)
// Register code actions (editor context menus, terminal context menus, keyboard shortcuts)
registerCodeActions(context, provider)
registerCodeActions(context, provider, agentManagerProvider)
registerTerminalActions(context, provider)
// Register CodeActionProvider (lightbulb quick fixes)
@@ -157,7 +157,7 @@ async function openKiloInNewTab(context: vscode.ExtensionContext, connectionServ
dark: vscode.Uri.joinPath(context.extensionUri, "assets", "icons", "kilo-dark.svg"),
}
const tabProvider = new KiloProvider(context.extensionUri, connectionService)
const tabProvider = new KiloProvider(context.extensionUri, connectionService, context)
tabProvider.resolveWebviewPanel(panel)
// Wait for the new panel to become active before locking the editor group.
@@ -0,0 +1,147 @@
import type { SessionInfo, AgentInfo, Provider, SSEEvent } from "./services/cli-backend/types"
export function sessionToWebview(session: SessionInfo) {
return {
id: session.id,
title: session.title,
createdAt: new Date(session.time.created).toISOString(),
updatedAt: new Date(session.time.updated).toISOString(),
}
}
export function normalizeProviders(all: Record<string, Provider>): Record<string, Provider> {
const normalized: Record<string, Provider> = {}
for (const provider of Object.values(all)) {
normalized[provider.id] = provider
}
return normalized
}
export function filterVisibleAgents(agents: AgentInfo[]): { visible: AgentInfo[]; defaultAgent: string } {
const visible = agents.filter((a) => a.mode !== "subagent" && !a.hidden)
const defaultAgent = visible.length > 0 ? visible[0]!.name : "code"
return { visible, defaultAgent }
}
export function buildSettingPath(key: string): { section: string; leaf: string } {
const parts = key.split(".")
const section = parts.slice(0, -1).join(".")
const leaf = parts[parts.length - 1]!
return { section, leaf }
}
export type WebviewMessage =
| {
type: "partUpdated"
sessionID: string
messageID: string
part: unknown
delta?: { type: "text-delta"; textDelta: string }
}
| {
type: "messageCreated"
message: { id: string; sessionID: string; role: string; createdAt: string; cost?: number; tokens?: unknown }
}
| { type: "sessionStatus"; sessionID: string; status: string; attempt?: number; message?: string; next?: number }
| {
type: "permissionRequest"
permission: {
id: string
sessionID: string
toolName: string
patterns: string[]
args: Record<string, unknown>
message: string
tool?: { messageID: string; callID: string }
}
}
| { type: "todoUpdated"; sessionID: string; items: unknown[] }
| { type: "questionRequest"; question: { id: string; sessionID: string; questions: unknown[]; tool?: unknown } }
| { type: "questionResolved"; requestID: string }
| { type: "sessionCreated"; session: ReturnType<typeof sessionToWebview> }
| { type: "sessionUpdated"; session: ReturnType<typeof sessionToWebview> }
| null
export function mapSSEEventToWebviewMessage(event: SSEEvent, sessionID: string | undefined): WebviewMessage {
switch (event.type) {
case "message.part.updated": {
const part = event.properties.part as { messageID?: string; sessionID?: string }
if (!sessionID) return null
return {
type: "partUpdated",
sessionID,
messageID: part.messageID || "",
part: event.properties.part,
delta: event.properties.delta ? { type: "text-delta", textDelta: event.properties.delta } : undefined,
}
}
case "message.updated":
return {
type: "messageCreated",
message: {
id: event.properties.info.id,
sessionID: event.properties.info.sessionID,
role: event.properties.info.role,
createdAt: new Date(event.properties.info.time.created).toISOString(),
cost: event.properties.info.cost,
tokens: event.properties.info.tokens,
},
}
case "session.status": {
const info = event.properties.status
return {
type: "sessionStatus",
sessionID: event.properties.sessionID,
status: info.type,
...(info.type === "retry" ? { attempt: info.attempt, message: info.message, next: info.next } : {}),
}
}
case "permission.asked":
return {
type: "permissionRequest",
permission: {
id: event.properties.id,
sessionID: event.properties.sessionID,
toolName: event.properties.permission,
patterns: event.properties.patterns ?? [],
args: event.properties.metadata,
message: `Permission required: ${event.properties.permission}`,
tool: event.properties.tool,
},
}
case "todo.updated":
return {
type: "todoUpdated",
sessionID: event.properties.sessionID,
items: event.properties.items,
}
case "question.asked":
return {
type: "questionRequest",
question: {
id: event.properties.id,
sessionID: event.properties.sessionID,
questions: event.properties.questions,
tool: event.properties.tool,
},
}
case "question.replied":
case "question.rejected":
return {
type: "questionResolved",
requestID: event.properties.requestID,
}
case "session.created":
return {
type: "sessionCreated",
session: sessionToWebview(event.properties.info),
}
case "session.updated":
return {
type: "sessionUpdated",
session: sessionToWebview(event.properties.info),
}
default:
return null
}
}
@@ -1,6 +1,7 @@
import * as vscode from "vscode"
import { t } from "./shims/i18n"
import type { AutocompleteStatusBarStateProps } from "./types"
import { humanFormatSessionCost, formatTime } from "./statusbar-utils"
const SUPPORTED_PROVIDER_DISPLAY_NAME = "Kilo Gateway"
@@ -40,14 +41,7 @@ export class AutocompleteStatusBar {
}
private humanFormatSessionCost(): string {
const cost = this.props.totalSessionCost
if (cost === 0) {
return t("kilocode:autocomplete.statusBar.cost.zero")
}
if (cost > 0 && cost < 0.01) {
return t("kilocode:autocomplete.statusBar.cost.lessThanCent")
}
return `$${cost.toFixed(2)}`
return humanFormatSessionCost(this.props.totalSessionCost)
}
public update(params: Partial<AutocompleteStatusBarStateProps>) {
@@ -60,8 +54,7 @@ export class AutocompleteStatusBar {
}
private formatTime(timestamp: number): string {
const date = new Date(timestamp)
return date.toLocaleTimeString()
return formatTime(timestamp)
}
private renderDefault() {
@@ -4,6 +4,7 @@ import { removePrefixOverlap } from "../continuedev/core/autocomplete/postproces
import { AutocompleteTelemetry } from "../classic-auto-complete/AutocompleteTelemetry"
import { postprocessAutocompleteSuggestion } from "../classic-auto-complete/uselessSuggestionFilter"
import type { KiloConnectionService } from "../../cli-backend"
import { finalizeChatSuggestion, buildChatPrefix } from "./chat-autocomplete-utils"
export class ChatTextAreaAutocomplete {
private model: AutocompleteModel
@@ -134,52 +135,17 @@ TASK: Complete the user's message naturally.
}
private async buildPrefix(userText: string, visibleCodeContext?: VisibleCodeContext): Promise<string> {
const contextParts: string[] = []
// Add visible code context (replaces cursor-based prefix/suffix)
if (visibleCodeContext && visibleCodeContext.editors.length > 0) {
contextParts.push("// Code visible in editor:")
for (const editor of visibleCodeContext.editors) {
const fileName = editor.filePath.split("/").pop() || editor.filePath
contextParts.push(`\n// File: ${fileName} (${editor.languageId})`)
for (const range of editor.visibleRanges) {
contextParts.push(range.content)
}
}
}
contextParts.push("\n// User's message:")
contextParts.push(userText)
return contextParts.join("\n")
return buildChatPrefix(userText, visibleCodeContext?.editors)
}
public cleanSuggestion(suggestion: string, userText: string): string {
let cleaned = postprocessAutocompleteSuggestion({
const cleaned = postprocessAutocompleteSuggestion({
suggestion: removePrefixOverlap(suggestion, userText),
prefix: userText,
suffix: "", // Chat textarea has no suffix
suffix: "",
model: this.model.getModelName() ?? "unknown",
})
if (cleaned === undefined) {
return ""
}
// Filter suggestions that look like code rather than natural language
if (cleaned.match(/^(\/\/|\/\*|\*|#)/)) {
return ""
}
// Chat-specific: truncate at first newline for single-line suggestions
const firstNewline = cleaned.indexOf("\n")
if (firstNewline !== -1) {
cleaned = cleaned.substring(0, firstNewline)
}
cleaned = cleaned.trimEnd()
return cleaned
if (cleaned === undefined) return ""
return finalizeChatSuggestion(cleaned)
}
}
@@ -0,0 +1,45 @@
/**
* Apply chat-specific post-processing to a suggestion:
* - Filter suggestions that look like code comments
* - Truncate at first newline (chat is single-line)
* - Trim trailing whitespace
* Returns empty string when the suggestion should be discarded.
*/
export function finalizeChatSuggestion(cleaned: string): string {
if (!cleaned) return ""
if (cleaned.match(/^(\/\/|\/\*|\*|#)/)) {
return ""
}
const firstNewline = cleaned.indexOf("\n")
const truncated = firstNewline !== -1 ? cleaned.substring(0, firstNewline) : cleaned
return truncated.trimEnd()
}
/**
* Build the prefix string for a chat completion request from user text and visible code context.
*/
export function buildChatPrefix(
userText: string,
editors?: Array<{
filePath: string
languageId: string
visibleRanges: Array<{ content: string }>
}>,
): string {
const parts: string[] = []
if (editors && editors.length > 0) {
parts.push("// Code visible in editor:")
for (const editor of editors) {
const fileName = editor.filePath.split("/").pop() || editor.filePath
parts.push(`\n// File: ${fileName} (${editor.languageId})`)
for (const range of editor.visibleRanges) {
parts.push(range.content)
}
}
}
parts.push("\n// User's message:")
parts.push(userText)
return parts.join("\n")
}
@@ -13,6 +13,15 @@ import {
AutocompleteContext,
LastSuggestionInfo,
} from "../types"
import {
findMatchingSuggestion as _findMatchingSuggestion,
applyFirstLineOnly as _applyFirstLineOnly,
countLines as _countLines,
shouldShowOnlyFirstLine as _shouldShowOnlyFirstLine,
getFirstLine as _getFirstLine,
calcDebounceDelay,
MatchingSuggestionWithFillIn as _MatchingSuggestionWithFillIn,
} from "./inline-utils"
import { HoleFiller } from "./HoleFiller"
import { FimPromptBuilder } from "./FillInTheMiddle"
import { AutocompleteModel } from "../AutocompleteModel"
@@ -59,101 +68,21 @@ const LATENCY_SAMPLE_SIZE = 10
export type { CostTrackingCallback, AutocompletePrompt, MatchingSuggestionResult, LLMRetrievalResult }
/**
* Result from findMatchingSuggestion including the original suggestion for telemetry tracking
*/
export interface MatchingSuggestionWithFillIn extends MatchingSuggestionResult {
/** The original FillInAtCursorSuggestion for telemetry tracking */
fillInAtCursor: FillInAtCursorSuggestion
}
export type MatchingSuggestionWithFillIn = _MatchingSuggestionWithFillIn
/**
* Find a matching suggestion from the history based on current prefix and suffix.
*
* @param prefix - The text before the cursor position
* @param suffix - The text after the cursor position
* @param suggestionsHistory - Array of previous suggestions (most recent last)
* @returns The matching suggestion with match type and the original FillInAtCursorSuggestion, or null if no match found
*/
export function findMatchingSuggestion(
prefix: string,
suffix: string,
suggestionsHistory: FillInAtCursorSuggestion[],
): MatchingSuggestionWithFillIn | null {
// Search from most recent to least recent
for (let i = suggestionsHistory.length - 1; i >= 0; i--) {
const fillInAtCursor = suggestionsHistory[i]
// First, try exact prefix/suffix match
if (prefix === fillInAtCursor.prefix && suffix === fillInAtCursor.suffix) {
return {
text: fillInAtCursor.text,
matchType: "exact",
fillInAtCursor,
}
}
// If no exact match, but suggestion is available, check for partial typing
// The user may have started typing the suggested text
if (fillInAtCursor.text !== "" && prefix.startsWith(fillInAtCursor.prefix) && suffix === fillInAtCursor.suffix) {
// Extract what the user has typed between the original prefix and current position
const typedContent = prefix.substring(fillInAtCursor.prefix.length)
// Check if the typed content matches the beginning of the suggestion
if (fillInAtCursor.text.startsWith(typedContent)) {
// Return the remaining part of the suggestion (with already-typed portion removed)
return {
text: fillInAtCursor.text.substring(typedContent.length),
matchType: "partial_typing",
fillInAtCursor,
}
}
}
// Check for backward deletion: user deleted characters from the end of the prefix
// The stored prefix should start with the current prefix (current is shorter)
// Only use this logic if the original suggestion is non-empty
if (fillInAtCursor.text !== "" && fillInAtCursor.prefix.startsWith(prefix) && suffix === fillInAtCursor.suffix) {
// Extract the deleted portion of the prefix
const deletedContent = fillInAtCursor.prefix.substring(prefix.length)
// Return the deleted portion plus the original suggestion text
return {
text: deletedContent + fillInAtCursor.text,
matchType: "backward_deletion",
fillInAtCursor,
}
}
}
return null
return _findMatchingSuggestion(prefix, suffix, suggestionsHistory)
}
/**
* Transforms a matching suggestion result by applying first-line-only logic if needed.
* Use this at call sites where you want to show only the first line of multi-line completions
* when the cursor is in the middle of a line.
*
* @param result - The result from findMatchingSuggestion
* @param prefix - The text before the cursor position
* @returns A new result with potentially truncated text, or null if input was null
*/
export function applyFirstLineOnly(
result: MatchingSuggestionWithFillIn | null,
prefix: string,
): MatchingSuggestionWithFillIn | null {
if (result === null || result.text === "") {
return result
}
if (shouldShowOnlyFirstLine(prefix, result.text)) {
const firstLineText = getFirstLine(result.text)
return {
text: firstLineText,
matchType: result.matchType,
fillInAtCursor: result.fillInAtCursor,
}
}
return result
return _applyFirstLineOnly(result, prefix)
}
/**
@@ -162,76 +91,16 @@ export function applyFirstLineOnly(
*/
export const INLINE_COMPLETION_ACCEPTED_COMMAND = "kilocode.autocomplete.inline-completion.accepted"
/**
* Counts the number of lines in a text string.
*
* Notes:
* - Returns 0 for an empty string
* - A single trailing newline (or CRLF) does not count as an additional line
*
* @param text - The text to count lines in
* @returns The number of lines
*/
export function countLines(text: string): number {
if (text === "") {
return 0
}
// Count line breaks and add 1 for the first line.
// If the text ends with a line break, don't count the implicit trailing empty line.
const lineBreakCount = (text.match(/\r?\n/g) || []).length
const endsWithLineBreak = text.endsWith("\n")
return lineBreakCount + 1 - (endsWithLineBreak ? 1 : 0)
return _countLines(text)
}
/**
* Determines if only the first line of a completion should be shown.
*
* The logic is:
* - If the suggestion starts with a newline → show the whole block
* - If the prefix's last line has non-whitespace text → show only the first line
* - If at start of line and suggestion is 3+ lines → show only the first line
* - Otherwise → show the whole block
*
* @param prefix - The text before the cursor position
* @param suggestion - The completion text being suggested
* @returns true if only the first line should be shown
*/
export function shouldShowOnlyFirstLine(prefix: string, suggestion: string): boolean {
// If the suggestion starts with a newline, show the whole block
if (suggestion.startsWith("\n") || suggestion.startsWith("\r\n")) {
return false
}
// Check if the current line (before cursor) has non-whitespace text
const lastNewlineIndex = prefix.lastIndexOf("\n")
const currentLinePrefix = prefix.slice(lastNewlineIndex + 1)
// if the first line contains no word characters, show the whole block
if (!currentLinePrefix.match(/\w/)) {
return false
}
// If the current line prefix contains non-whitespace, only show the first line
if (currentLinePrefix.trim().length > 0) {
return true
}
// At start of line (only whitespace before cursor on this line)
// Show only first line if suggestion is 3 or more lines
const lineCount = countLines(suggestion)
return lineCount >= 3
return _shouldShowOnlyFirstLine(prefix, suggestion)
}
/**
* Extracts the first line from a completion text.
*
* @param text - The full completion text
* @returns The first line of the completion (without the newline)
*/
export function getFirstLine(text: string): string {
return text.split(/\r?\n/, 1)[0]
return _getFirstLine(text)
}
export function stringToInlineCompletions(text: string, position: vscode.Position): vscode.InlineCompletionItem[] {
@@ -398,19 +267,10 @@ export class AutocompleteInlineCompletionProvider implements vscode.InlineComple
* @param latencyMs - The latency of the most recent request in milliseconds
*/
public recordLatency(latencyMs: number): void {
// Add the new latency to the history
this.latencyHistory.push(latencyMs)
// Remove oldest if we exceed the sample size
if (this.latencyHistory.length > LATENCY_SAMPLE_SIZE) {
this.latencyHistory.shift()
// Once we have enough samples, update the debounce delay to the average
const sum = this.latencyHistory.reduce((acc, val) => acc + val, 0)
const averageLatency = Math.round(sum / this.latencyHistory.length)
// Clamp the debounce delay between MIN and MAX
this.debounceDelayMs = Math.max(MIN_DEBOUNCE_DELAY_MS, Math.min(averageLatency, MAX_DEBOUNCE_DELAY_MS))
this.debounceDelayMs = calcDebounceDelay(this.latencyHistory)
}
}
@@ -1,14 +1,11 @@
import { TelemetryProxy, TelemetryEventName } from "../../telemetry"
import type { AutocompleteContext, CacheMatchType, FillInAtCursorSuggestion } from "../types"
import { getSuggestionKey as _getSuggestionKey, insertWithLRUEviction } from "./telemetry-utils"
export type { AutocompleteContext, CacheMatchType, FillInAtCursorSuggestion }
/**
* Generate a unique key for a suggestion based on its content and context.
* This key is used to track whether the same suggestion is still being displayed.
*/
export function getSuggestionKey(suggestion: FillInAtCursorSuggestion): string {
return `${suggestion.prefix}|${suggestion.suffix}|${suggestion.text}`
return _getSuggestionKey(suggestion)
}
/**
@@ -64,14 +61,7 @@ export class AutocompleteTelemetry {
private firedUniqueTelemetryKeys: Map<string, true> = new Map()
private markSuggestionKeyAsFired(suggestionKey: string): void {
this.firedUniqueTelemetryKeys.set(suggestionKey, true)
if (this.firedUniqueTelemetryKeys.size > MAX_FIRED_UNIQUE_TELEMETRY_KEYS) {
const oldestKey = this.firedUniqueTelemetryKeys.keys().next().value as string | undefined
if (oldestKey) {
this.firedUniqueTelemetryKeys.delete(oldestKey)
}
}
insertWithLRUEviction(this.firedUniqueTelemetryKeys, suggestionKey, MAX_FIRED_UNIQUE_TELEMETRY_KEYS)
}
/**

Some files were not shown because too many files have changed in this diff Show More