feat(vscode): multi-project Agent Manager - #12566
Conversation
…sions, and lifecycle Add an experimental multi-project mode to the Agent Manager sidebar behind kilo-code.new.experimental.multiProject (default off). A persistent project registry catalogs additional git repositories across restarts, while the workspace repository stays the pinned default project. Extension: - Immutable per-project contexts own all repository-bound services (state, worktrees, setup scripts, stale tracking, pollers) with generation-based invalidation and fail-closed trust checks. - ProjectContexts manage activation, expansion, and fast switching; session routes resolve directories exactly per project via a shared route service. - pushProjectSessions caches each project's session list and re-posts it on fresh skips; session.created/updated/deleted SSE events upsert into the owning project's cache so externally created sessions appear immediately. - Selection restore persists the active target per project and falls back to the local context silently when the remembered target is gone. - Worktree lifecycle handlers extracted into provider-lifecycle.ts with an explicit deps object instead of ambient project scope. - initializeState and onRequestState always refresh sessions: with zero managed sessions the listing never ran and the sidebar skeletons forever. - Log instead of dropping silently when a state-gated message is not ready. Webview: - ProjectList accordion with per-project sidebar body, search, actions, and default-branch dialog; selecting a project header restores its target. - Local session tabs and terminal contexts are bucketed per project so open tabs never leak across projects sharing the LOCAL context. - The active project's session list overlays the live session store so new sessions show without waiting for a backend re-list. - SectionHeader requires a DragDropProvider ancestor; the multi-project body now provides one (its absence crashed the whole webview render). - SidebarBody and TabBar extracted out of AgentManagerApp (3215 to 2748 lines); AgentManagerProvider down to 1887 with caps lowered accordingly. Also includes the config write revision bindings and per-project indexing consent groundwork that rode along on this branch.
Code Review SummaryStatus: 4 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING (new this pass)
WARNING (still unresolved from earlier passes, already commented)
Scope of this incremental passSince the last review ( Merge conflict resolutions (
Assumptions: no build, typecheck, lint, or test commands were run (read-only mode), so CI-detectable problems are deliberately out of scope. Findings on files with no genuine net PR diff, and on unchanged lines, were excluded. Files Reviewed (9 files with PR-authored changes in this window)
Fix these issues in Kilo Cloud Previous Review Summaries (8 snapshots, latest commit e60b06e)Current summary above is authoritative. Previous snapshots are kept for context only. Previous review (commit e60b06e)Status: No Issues Found | Recommendation: Merge Incremental pass since commit Genuine PR-authored changes in this window:
Re-verified the 2 previously-flagged WARNINGs in Files Reviewed (incremental: files changed since 9bbf2da with a genuine net PR diff)
Previous review (commit 9bbf2da)Status: 2 Issues Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (incremental: files changed since 6617b24)
Note: 3 previously-flagged WARNING comments remain open on files untouched by this incremental diff ( Fix these issues in Kilo Cloud Previous review (commit 6617b24)Status: No Issues Found | Recommendation: Merge Incremental review since Note: 3 previously-flagged WARNING comments remain open on files untouched by this incremental diff ( Files Reviewed (incremental: 4 files since c271a8e)
Previous review (commit c271a8e)Status: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (incremental: 2 files since 1064ce9)Reviewed the incremental diff against the previous review (
Fix these issues in Kilo Cloud Previous review (commit 1064ce9)Status: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (incremental: 3 files since f6a1725)Reviewed the incremental diff against the previous review (
Fix these issues in Kilo Cloud Previous review (commit f6a1725)Status: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (incremental: 13 files since 2108dc5)Reviewed the incremental diff against the previous review (
Fix these issues in Kilo Cloud Previous review (commit 2108dc5)Status: 1 Issue Found | Recommendation: Address before merge Overview
Issue Details (click to expand)WARNING
Files Reviewed (incremental: 3 files since ae28bad)Reviewed the incremental diff against the previous review (
Fix these issues in Kilo Cloud Previous review (commit ae28bad)Status: No Issues Found | Recommendation: Merge Files Reviewed (incremental: 3 files since 8093fed)Reviewed the incremental diff against the previous review (
[Snapshot truncated.] Additional previous summary content was truncated to keep this comment within platform limits. Reviewed by claude-opus-5 · Input: 138 · Output: 32.1K · Cached: 6.7M Review guidance: REVIEW.md from base branch |
…ings CI: - Render the config console's active overlay target from its new object shape instead of passing it to JSX. - Make the config overlay `expected` revision optional in the schema, writer, and handler so clients without a binding write unconditionally instead of receiving a 400, and add the missing PUT /indexing/consent exerciser scenario. Regenerate the SDK for the schema change. - The multi-project Storybook story called useLanguage() outside its provider and rendered nothing; it now uses the story translator. - Scope indexing test select locators by row title, since the tab gained a project selector that shifted positional lookups. Review findings: - Gate worktree creation, promotion, and multi-version creation on the target project's state: waitForStateReady only tracked the active project, so those handlers could mutate a background project's state before it loaded. - Re-check trust and enablement for every project-stamped message instead of resolving contexts through the unchecked map lookup. - Register projects through resolveProjectRoot so a folder inside a linked worktree cannot duplicate an existing project, and fix that helper to issue valid rev-parse commands. - Validate the persisted activeTarget shape before applying it. - Stop throwing from workspace/session directory resolution: it runs eagerly per webview message, where a throw dropped the message. - Evict superseded config bindings per scope and directory. - Guard the multi-project rename against the blur that Escape triggers. - Unregister routes when disabling secondary projects. - Replace the section message substring test with an explicit type set. - Match an open session tab in the project search's current item and scope selection acks by project id. - Filter untrusted projects out of indexing consent, and restore config scope switching plus project-scoped indexing writes that the consent rework had removed. - Round-trip the sessions-collapsed mutation so multi-project bodies, which render purely from pushed state, reflect the toggle.
…s up The active guard required both activeProjectId and currentProjectId to match the ack's project, but reactivation pushes state asynchronously, so the ack can arrive before the state push flips currentProjectId. The catalog push is synchronous, so activeProjectId alone is sufficient to scope the ack. The worktree callback no longer requires the target worktree to already be present in the applied state; the top-level guard scopes by project and the arriving state reconciles.
…essions Two bugs made local tabs feel shared across projects: 1. On activation the extension pushes state before the catalog, so the applyState gate rejected the payload for the newly active project and currentProjectId never flipped; the tab bar kept reading the previous project's local tab bucket. State for a not-yet-catalog-active project is now deferred and applied when the catalog marks it active. 2. Clicking an unassigned session in a project's session list selected it without adding it to the project's local tab bucket. The selection ack now opens the session as a tab, mirroring the legacy sidebar.
…odules Group the multi-project webview logic under agent-manager/project/: - state.ts: createProjectStateRouter, the catalog/state ordering and deferral logic, now unit-tested (state-before-catalog, catalog-first, pending flush, removal pruning) - selection.ts: selection ack application plus the target rememberer - restore.ts, live.ts, sessions-live.ts, local-tabs.ts: moved as-is No behavior change.
…mory Replace the tabKey/memKey bucket keying with a project registry: - project/store.ts: createProjectStore owns one project's local session tabs and per-context tab memory as plain signals - project/registry.ts: createProjectRegistry holds stores per project, exposes a single active-store accessor driven by the applied project, migrates legacy single-project tabs once into the first real project, and prunes stores for removed projects - Terminal contexts use one nsKey driven by the applied project, removing the catalog-vs-applied identity split that could key tabs and terminals to different projects during a switch - createLocalTabs superseded; bucket tests moved to the registry suite Verified end to end: tab isolation across projects, session clicks opening tabs, and project switches restoring each project's own tabs.
Expand ProjectStore to own every per-project signal: worktrees, managed sessions, sections, orders, stale ids, collapsed state, default base branch, run script config, PR and run statuses, worktree and local git stats, apply state, busy state, local tabs, and tab memory. App's shared signals are now thin delegates over the active project's store, so all existing readers and writers keep working unchanged while ownership lives per project. Live poller payloads (worktree/local/PR stats) are written into their owning project's store via the registry, so background projects accumulate live data in the same shape the active project uses. ApplyState and WorktreeBusyState move into the store as exported types.
…store Data fields of agentManager.state now land in the payload's own ProjectStore via store.applyState, unconditionally. The catalog/state router now handles only the active-transition effects (selection and tab restore, view preferences), which is the only part that still depends on catalog ordering. Background projects accumulate complete, current state in their stores, so any of them can become active without a reload. New-section rename detection moved ahead of the data write since it diffs against the previous section list.
…apability host The worktree lifecycle handlers took a 27-field closure bag that mixed project-state accessors with provider capabilities, a service-locator pattern with the same hidden-dependency problem as the ambient scope it replaced. Handlers now receive the ProjectContext directly for everything that is project state (peekState, worktreeManager, stale set, root, readiness via initContextState), and a small LifecycleHost carries only what genuinely belongs to the provider: the shared creation helpers, the panel session facade, route registration, poller skips, the diff controller, telemetry, and the webview boundary. The provider resolves ctx explicitly at each handler boundary.
# Conflicts: # packages/kilo-vscode/eslint.config.mjs # packages/kilo-vscode/package.json # packages/kilo-vscode/src/KiloProvider.ts # packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts # packages/kilo-vscode/src/agent-manager/types.ts # packages/kilo-vscode/src/agent-manager/vscode-host.ts # packages/kilo-vscode/tests/unit/kilo-provider-indexing-refresh.test.ts # packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx # packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts # packages/sdk/openapi.json
…roject The project-domain modules sat flat in src/agent-manager next to the shared capability layer (GitOps, WorktreeStateManager, pollers, diff helpers), which made the layering invisible: anything could import anything and the folder gave no hint about what belongs to per-project state versus shared infrastructure. Moves the files whose entire reason to exist is per-project state and routing into src/agent-manager/project/: context (split from the old project-context.ts into context.ts for the single-project scope and contexts.ts for the panel-level coordinator), init, paths, registry, route, scope, pollers, messages, session-view, state-gate, and wiring. Shared capabilities stay at the parent level; the domain imports them across the boundary (../GitOps etc.), the same pattern the webview project/ directory already uses. Rename-only aside from the context split and import path updates; no barrel module.
…module onCreateMultiVersion was a 180-line orchestration method on the provider, and the merge pushed AgentManagerProvider past its 1900-line arch cap. The flow moves to provider-multi-version.ts next to provider-lifecycle.ts and follows the same pattern: state comes from the ProjectContext, and a MultiVersionHost (extending LifecycleHost with worktree discard, the branch naming prompt, and error reporting) carries provider capabilities. The flow is decomposed along its existing phase boundaries to satisfy the complexity limit: createVersion (one worktree + session, sandbox gate, exposure), reconcileSandbox (rollback on failure), and sendInitialPrompts (Phase 2 fan-out). Behavior is unchanged; the sandbox ordering test now asserts per-function wiring instead of cross-function source order.
# Conflicts: # packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts # packages/kilo-vscode/src/agent-manager/host.ts # packages/kilo-vscode/src/agent-manager/vscode-host.ts # packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
The corrupted-cache recovery in ModelsDev.populate acquired the flock and fetched unconditionally, while the background refresh fiber runs the same recovery on layer build. When refresh won the lock race it rewrote a valid cache file, but populate still fetched again because it never re-read the cache after acquiring the lock. The result was a duplicated network call, which the corrupted-cache test catches as calls.length == 2 on slow CI runners (fast local machines almost always take the single-fetch path). Re-run loadFromDisk under the flock, mirroring the re-check refresh already performs, so whichever fiber recovers second reuses the valid cache instead of refetching.
The RunScriptManager keys entries by worktreeId and the webview sends "local" for whichever project's local context is selected, so in multi-project mode two projects' local runs collided in one entry: a second project's Run button stopped the first project's script, and the state payload spread every project's run statuses into the active project's push, rendering foreign local rows as running. The provider now namespaces the local key as <projectId>:local at the message boundary (ambient project scope, no webview protocol change), RunController treats the qualified suffix as a local run (repo root cwd, "local" branch label), each project's state payload is filtered to its own worktrees plus its un-namespaced local key, and runStatus emissions are routed with a projectId stamp so background-project statuses land in their own webview store. ScriptTerminalManager keys inherit the same qualification, and its view mapping already namespaces run terminals to the matching project bucket.
feat(vscode): multi-project Agent Manager
Adds an experimental multi-project mode to the Agent Manager sidebar, gated behind
kilo-code.new.experimental.multiProject(default off). Single-project behavior is unchanged when the experiment is disabled.Why
Agent Manager currently operates on exactly one repository: the workspace root. Users working across several repos have to open one window per repo and lose the unified worktree/session overview. This branch introduces a persistent project registry so additional git repositories can live side by side in one sidebar, each with its own worktrees, sections, sessions, git stats, and PR badges.
What changes
Extension
ProjectContext/ProjectContexts) own every repository-bound service: state manager, worktree manager, setup scripts, stale tracking, git stats and PR pollers. Generations invalidate async work; trust checks are fail-closed before any state load.session.created/updated/deletedSSE events upsert into the owning project's cached list (resolved by directory), so sessions created from the CLI, another window, or the API appear immediately.provider-lifecycle.tswith an explicit deps object, removing ambient AsyncLocalStorage scope from those paths.Webview
ProjectList/ProjectsSection/ProjectSidebarBody) renders each project's real sidebar body with worktree ordering, sections, sessions, and the full action set (search, new worktree, sections, settings, keyboard shortcuts).Notable bug fixes included
SectionHeaderregisters a solid-dnd drop target and throws without aDragDropProviderancestor. The multi-project body rendered it without one, which killed the entire Solid tree on the first state push (stuck skeletons, dead interactions, sessions/sections/deletes all appearing "broken").initializeState/onRequestStateonly refreshed sessions when managed sessions existed, sosessionsLoadednever reached the webview and both sidebar sections skeleton'd forever. Refreshes are now unconditional.Scale guardrails
The arch test caps both oversized files and they now sit well under:
AgentManagerProvider.ts1998 to 1764 (cap 2000 to 1900),AgentManagerApp.tsx3215 to 2558 (eslint cap 3210 to 2800). The extractions (SidebarBody.tsx,TabBar.tsx,provider-lifecycle.ts,provider-multi-version.ts,src/agent-manager/project/) are covered by delegation-aware arch tests.Note: this branch also carries the config write revision bindings and per-project indexing consent groundwork that preceded it. Known follow-ups are tracked in
.kilo/plans/agent-manager-multi-project-shipping-gaps.md; the two sidebar parity items have dedicated issues: #12685 (section support in multi-project mode) and #12686 (sidebar drag-and-drop in multi-project mode).