Skip to content

feat(vscode): multi-project Agent Manager - #12566

Merged
marius-kilocode merged 23 commits into
mainfrom
abalone-bactrosaurus
Jul 30, 2026
Merged

feat(vscode): multi-project Agent Manager#12566
marius-kilocode merged 23 commits into
mainfrom
abalone-bactrosaurus

Conversation

@marius-kilocode

@marius-kilocode marius-kilocode commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

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.

file-6d4cee08d6044bbbaf8366de0a8f2156 file-c0ccaded9911f8fad22e3d23dfa473ba image

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

  • Immutable per-project contexts (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.
  • Fast project switching: reactivation skips full init when the context is still ready, session listings are cached per project, and fresh skips re-post the cached list instead of nothing.
  • Sessions stay live without manual refresh: session.created/updated/deleted SSE 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.
  • Selection restore: each project persists its active sidebar target; clicking a project header restores exactly that worktree/session, and stale targets fall back to the local context silently instead of erroring.
  • The worktree lifecycle handlers (create/delete/promote/add/close) are extracted into provider-lifecycle.ts with an explicit deps object, removing ambient AsyncLocalStorage scope from those paths.

Webview

  • A project accordion (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).
  • Open LOCAL session tabs and terminal contexts are bucketed per project, so tabs opened in one project never appear under another.
  • The active project's session list overlays the live session store, so newly created sessions show up without waiting for a backend re-list.

Notable bug fixes included

  • Webview render crash in multi-project mode: SectionHeader registers a solid-dnd drop target and throws without a DragDropProvider ancestor. 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").
  • Permanent skeletons with an empty session list: initializeState/onRequestState only refreshed sessions when managed sessions existed, so sessionsLoaded never reached the webview and both sidebar sections skeleton'd forever. Refreshes are now unconditional.
  • Poller busy-flag race test: documents and locks in the mutual-exclusion invariant when a poll is stopped mid-flight and restarted.

Scale guardrails

The arch test caps both oversized files and they now sit well under: AgentManagerProvider.ts 1998 to 1764 (cap 2000 to 1900), AgentManagerApp.tsx 3215 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).

…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.
Comment thread packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts
Comment thread packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts
Comment thread packages/kilo-vscode/src/agent-manager/project-context.ts Outdated
Comment thread packages/kilo-vscode/src/agent-manager/project-messages.ts Outdated
Comment thread packages/kilo-vscode/src/agent-manager/WorktreeStateManager.ts Outdated
Comment thread packages/kilo-vscode/src/KiloProvider.ts
Comment thread packages/kilo-vscode/src/kilo-provider/config-bindings.ts
Comment thread packages/kilo-vscode/webview-ui/agent-manager/ProjectList.tsx
Comment thread packages/kilo-vscode/webview-ui/agent-manager/project-selection.ts Outdated
@kilo-code-bot

kilo-code-bot Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Code Review Summary

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 4
SUGGESTION 0
Issue Details (click to expand)

WARNING (new this pass)

File Line Issue
packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts 1373 Run-script state is provider-wide but keyed by worktree id, so "local" collides across projects: run.state() returns manager.all(), so project A's local run status leaks into project B's push and pressing Run in B stops A's script. handleRunMessage also drops the projectId now carried on agentManager.runScript.

WARNING (still unresolved from earlier passes, already commented)

File Line Issue
packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx 1426 local selection ack ignores projectId
packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx 952 registry.prune is never called, so per-project tab/tabMemory stores leak
packages/kilo-vscode/webview-ui/agent-manager/project/selection.ts 33 openTab runs before deps.local, bucketing the tab under the wrong project
Scope of this incremental pass

Since the last review (e60b06e13e) the branch has exactly two commits: a merge from main and fix(core): re-check models.dev cache under the flock before refetching. Almost all of the apparent incremental diff is unrelated upstream code arriving through the merge, so the review was narrowed to (a) the merge's conflict resolutions and (b) the one author commit.

Merge conflict resolutions (git show <merge> --cc) integrate upstream's retained Run-script terminal work into the PR's refactored files. Each resolution was compared against main's implementation and is faithful: unskipStats/clearRun added to LifecycleHost with the same skipStats -> removeRun -> clearRun -> unskip-on-failure ordering as upstream onDeleteWorktree/onRemoveStaleWorktree; isTrusted() added to Host/VscodeHost; ScriptTerminalsMessage + destination on RunScriptIn/RunScriptRequest; scripts.manager.intercept still ordered before terminalRouter.handle (now in dispatchMessage); scripts.manager.snapshot() and await this.scripts.dispose() at the same call sites as upstream; TabBar's onRun now resolves sideCtl.destination() at click time. Upstream's sideCtl.echo()/sideCtl.press keydown fallback, onScriptRunning, and cleanup were all verified present at HEAD. The arch test was updated in lockstep (body("dispatchMessage"), host.clearRun / host.skipStats) and still follows delegation into provider-lifecycle.ts.

packages/core/src/models-dev.ts re-reads the cache under the flock before refetching, mirroring the existing pattern in refresh(). Correct: the outer loadFromDisk already removed a corrupt file, so a successful recheck means another process just wrote a good one, and the duplicate fetch is skipped. This commit is unrelated to the multi-project feature and is not mentioned in the PR description.

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)
  • packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts - 1 issue
  • packages/kilo-vscode/src/agent-manager/provider-lifecycle.ts - no issues
  • packages/kilo-vscode/src/agent-manager/host.ts - no issues
  • packages/kilo-vscode/src/agent-manager/vscode-host.ts - no issues
  • packages/kilo-vscode/src/agent-manager/types.ts - no issues
  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx - no new issues (2 earlier WARNINGs re-verified as still reproducing)
  • packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts - no issues
  • packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts - no issues
  • packages/core/src/models-dev.ts - no issues

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 9bbf2dab10. The apparent diff against that point is large because the branch was rebased onto main, pulling in unrelated upstream commits (diff scope selector, prompt navigation, docs, i18n, jetbrains). Scope was narrowed to files with a genuine net diff against the PR's current base (gh pr diff --name-only) that also changed since the last review.

Genuine PR-authored changes in this window:

  • AgentManagerProvider.ts / provider-multi-version.ts: extracted createMultiVersion into its own module with a MultiVersionHost interface — behavior preserved (worktree creation, sandbox reconciliation/rollback, initial prompt fan-out all match the prior inline implementation).
  • types.ts, webview-messages.ts, extension-messages.ts: new agentManager.requestDiffBranches / setDiffBaseBranch / diffBranches message types and scope fields, wired consistently end to end.
  • AgentManagerApp.tsx, TabBar.tsx: integrate the (separately-merged) diff scope selector — reviewDiffs/diffScopeId now key off the composite scope id instead of scanning managedSessions(); Apply button now gates on reviewScope() === "branch". No correctness issues found in the changed lines.
  • KiloProvider.ts / config-snapshot.ts / context/config.tsx: plumb a new collections field through the config snapshot — mechanical, no issues.
  • agent-manager-arch.test.ts, sandbox-bootstrap.test.ts: updated in lockstep with the multi-version extraction; assertions still target real behavior (sandbox gate before exposure, rollback-before-abort ordering).

Re-verified the 2 previously-flagged WARNINGs in AgentManagerApp.tsx (lines 1411, 950) against the current file — both still reproduce (local: () => selectLocal() ack still ignores projectId; pruneLive: (ids) => projectLive.prune(ids) still only reachable if the router itself is invoked) but neither line was touched by this incremental diff, so they remain out of scope for this pass. project/selection.ts line 33 is likewise unchanged and out of scope.

Files Reviewed (incremental: files changed since 9bbf2da with a genuine net PR diff)
  • .kilo/plans/agent-manager-multi-project-shipping-gaps.md - no issues (doc link to tracking issues)
  • packages/kilo-vscode/src/KiloProvider.ts - no issues
  • packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts - no issues (multi-version extraction verified equivalent)
  • packages/kilo-vscode/src/agent-manager/provider-multi-version.ts - no issues (new file, faithful extraction)
  • packages/kilo-vscode/src/agent-manager/types.ts - no issues
  • packages/kilo-vscode/src/kilo-provider/config-snapshot.ts - no issues
  • packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts - no issues
  • packages/kilo-vscode/tests/unit/sandbox-bootstrap.test.ts - no issues
  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx - no new issues (2 pre-existing WARNINGs re-verified, out of scope — unchanged lines)
  • packages/kilo-vscode/webview-ui/agent-manager/TabBar.tsx - no issues
  • packages/kilo-vscode/webview-ui/agent-manager/agent-manager.css - no issues
  • packages/kilo-vscode/webview-ui/agent-manager/i18n/*.ts (all languages) - no issues (translation string addition)
  • packages/kilo-vscode/webview-ui/src/context/config.tsx - no issues
  • packages/kilo-vscode/webview-ui/src/i18n/*.ts (all languages) - no issues (translation string additions)
  • packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx - no issues
  • packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts - no issues
  • packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts - no issues

Previous review (commit 9bbf2da)

Status: 2 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 2
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-vscode/webview-ui/agent-manager/apply-to-local.tsx 242 Apply state (applyStates/applyTarget) was moved out of the per-project store into a flat module-level signal, but its cleanup effect still filters by only the active project's worktrees(). Switching projects purges the previous project's apply status and can force-close its Apply dialog. GitHub could not resolve a valid diff position for an inline comment on this line, so it is reported here only.
packages/kilo-vscode/webview-ui/agent-manager/apply-to-local.tsx 77 applyDiffs dropped the fallback that scanned all managedSessions() for the target worktree when the primary session id lookup misses the diff cache. A worktree with more than one managed session (e.g. a superseded/promoted session) can now show an empty/stale diff list in the Apply dialog even though cached diff data exists. GitHub could not resolve a valid diff position for an inline comment on this line, so it is reported here only.
Files Reviewed (incremental: files changed since 6617b24)
  • packages/kilo-vscode/src/KiloProvider.ts - no new issues (config fetch/update consolidated into refreshConfig/fetchSnapshot, behavior preserved)
  • packages/kilo-vscode/src/kilo-provider/config-snapshot.ts - no new issues
  • packages/kilo-vscode/src/kilo-provider/early-message.ts - no new issues
  • packages/kilo-vscode/src/kilo-provider/options.ts - no new issues
  • packages/kilo-vscode/src/indexing-consent.ts - no new issues (import path rename only)
  • packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts - no new issues (terminal-destination watcher, terminal router dispose-on-mount/close, external-worktree message removal all verified correct)
  • packages/kilo-vscode/src/agent-manager/GitStatsPoller.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/WorktreeStateManager.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/host.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/provider-lifecycle.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/types.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/vscode-host.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/project/context.ts - no new issues (extracted from project-context.ts; verified byte-for-byte equivalent to pre-split behavior, including the previously-fixed disable()/remove()/syncPinned() logic)
  • packages/kilo-vscode/src/agent-manager/project/contexts.ts - no new issues (new coordinator extracted from project-context.ts, no dropped methods or behavior changes)
  • packages/kilo-vscode/src/agent-manager/project/init.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/project/messages.ts - no new issues (previously-fixed addProject/resolveProjectRoot logic still correct)
  • packages/kilo-vscode/src/agent-manager/project/paths.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/project/pollers.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/project/registry.ts - no new issues (pure move)
  • packages/kilo-vscode/src/agent-manager/project/route.ts - no new issues (pure move)
  • packages/kilo-vscode/src/agent-manager/project/scope.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/project/session-view.ts - no new issues (pure rename)
  • packages/kilo-vscode/src/agent-manager/project/state-gate.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/project/wiring.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-project-contexts.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-project-messages.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-project-paths.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-project-pollers.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-project-reactivate.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-project-route.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-project-selection.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-project-sessions.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/kilo-provider-indexing-refresh.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/kilo-provider-route-integration.test.ts - no new issues
  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx - no new issues in the reviewed diff scope
  • packages/kilo-vscode/webview-ui/agent-manager/TabBar.tsx - no new issues
  • packages/kilo-vscode/webview-ui/agent-manager/WorktreeItem.tsx - no new issues
  • packages/kilo-vscode/webview-ui/agent-manager/agent-manager.css - no new issues
  • packages/kilo-vscode/webview-ui/agent-manager/apply-to-local.tsx - 2 issues (see above)
  • packages/kilo-vscode/webview-ui/agent-manager/project/store.ts - no new issues (confirms applyStates removal, see apply-to-local.tsx findings)
  • packages/kilo-vscode/webview-ui/src/stories/StoryProviders.tsx - no new issues
  • packages/kilo-vscode/webview-ui/src/stories/agent-manager.stories.tsx - no new issues
  • packages/kilo-vscode/webview-ui/src/types/messages/extension-messages.ts - no new issues
  • packages/kilo-vscode/webview-ui/src/types/messages/sessions.ts - no new issues
  • packages/kilo-vscode/webview-ui/src/types/messages/webview-messages.ts - no new issues

Note: 3 previously-flagged WARNING comments remain open on files untouched by this incremental diff (AgentManagerApp.tsx lines 1403 and 946, project/selection.ts line 33) — out of scope for this pass per incremental review rules.

Fix these issues in Kilo Cloud

Previous review (commit 6617b24)

Status: No Issues Found | Recommendation: Merge

Incremental review since c271a8ea51de5d53648e08b5e9dc7003df312815 — the diff refactors the worktree lifecycle handlers to route through the new ProjectContext/LifecycleHost split (LifecycleDepsLifecycleHost, deps.state()/manager()ctx.peekState()/ctx.worktreeManager()) and updates the corresponding arch/unit tests. Verified the renamed capability paths (host.runSetup, host.sessions.abort/clearDirectory/directories/forget, host.stopDiffs, ctx.stale, ctx.root) are all correctly wired from AgentManagerProvider.ts's new lifecycleHost getter and this.context accessor, and that the updated arch-test string assertions (host.sessions.abort([sessionId]), worktreeManager().removeWorktree, host.runSetup(, host.createSession() match the current source. The agent-manager-close-session.test.ts mock now supplies projectScope/contexts consistent with the new ctx-based onCloseSession path. No behavior change identified beyond the parameter-passing refactor.

Note: 3 previously-flagged WARNING comments remain open on files untouched by this incremental diff (AgentManagerApp.tsx lines 1102 and 1591, project/selection.ts line 33) — out of scope for this pass per incremental review rules, left for a future round that touches those files.

Files Reviewed (incremental: 4 files since c271a8e)
  • packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts - no new issues
  • packages/kilo-vscode/src/agent-manager/provider-lifecycle.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-manager-arch.test.ts - no new issues
  • packages/kilo-vscode/tests/unit/agent-manager-close-session.test.ts - no new issues

Previous review (commit c271a8e)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx 1102 registry.prune is still never called from pruneLive, so removed projects' full per-project state (worktrees/sections/stats/apply state/tabs) leaks for the life of the webview
Files Reviewed (incremental: 2 files since 1064ce9)

Reviewed the incremental diff against the previous review (1064ce997a0abf237dad976340fd5b0fc73a2680...c271a8ea51de5d53648e08b5e9dc7003df312815). No new issues found in the changed lines.

  • packages/kilo-vscode/webview-ui/agent-manager/project/store.ts - createProjectStore gains applyState, which writes an incoming agentManager.state payload's data fields (worktrees, sessions, sections, tab/worktree order, defaultBaseBranch, run-script flag, sessionsCollapsed, run statuses, and busy-map reconciliation against the current worktree list) directly into the store, replacing the old syncRunStatuses free function and the busy-map filtering that previously lived in AgentManagerApp.tsx. Correctly constructed from the removed code with no logic change.
  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx - applyState (the agentManager.state message handler) now resolves the payload's owning store via pid ? registry.ensure(pid) : registry.active() and calls store.applyState(state) unconditionally for every payload, before router.routeState(state). This lands background projects' data in their own store instead of dropping it, matching the PR's stated data-freshness fix. The pendingNewSection new-section-id detection is correctly read from store.sections() before store.applyState() overwrites it. applyActiveState is narrowed to only the active-transition effects (selection/tab restore, isGitRepo/loaded flags, sidebar hydrate); no double-write of data fields observed. Re-verified the previously flagged registry.prune gap (WARNING above): still present, unrelated to lines touched by this diff.

Fix these issues in Kilo Cloud

Previous review (commit 1064ce9)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx 1108 registry.prune (per-project stores, now also holding worktrees/sections/stats/apply state) is still never called from pruneLive, so removed projects' full per-project state leaks for the life of the webview
Files Reviewed (incremental: 3 files since f6a1725)

Reviewed the incremental diff against the previous review (f6a172535f246c7393a422f8579aa7865bfe422e...1064ce997a0abf237dad976340fd5b0fc73a2680). No new issues found in the changed lines.

  • packages/kilo-vscode/webview-ui/agent-manager/project/store.ts - createProjectStore now owns the full per-project sidebar/live-data surface (worktrees, managedSessions, sections, staleWorktreeIds, tabOrder, worktreeOrder, sessionsCollapsed, defaultBaseBranch, runScriptConfigured, prStatuses, runStatuses, worktreeStats, localStats, applyStates, busy) via a small field() helper, moving WorktreeBusyState/ApplyState in from AgentManagerApp.tsx. Mechanical, well-factored extension of the existing per-project store.
  • packages/kilo-vscode/webview-ui/agent-manager/project/live.ts - createProjectLive is rewired from three ad hoc shared.stats/local/pr callbacks (fired only for the active project) to a deps.ensure(pid) that writes worktree/local/PR stats into the owning project's store unconditionally, plus a narrower deps.active/deps.branch pair used only to drive the local repo branch label. This fixes the underlying data-freshness gap the previous callback shape had for non-active projects and is consistent with the accordion's separate per-project stats/local/prs signals, which are unchanged.
  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx - Replaces the local WorktreeBusyState/ApplyState interfaces (now imported from project/store.ts) and rewires roughly a dozen local signals (worktrees, managedSessions, busyWorktrees, staleWorktreeIds, defaultBaseBranch, sections, worktreeStats, prStatuses, runStatuses, runScriptConfigured, localStats, applyStates, worktreeTabOrder, sidebarWorktreeOrder, sessionsCollapsed) to read/write through registry.active() instead of owning private createSignal state. The boolean sessionsCollapsed setter correctly resolves updater functions manually before writing, avoiding Solid's function-vs-value setter ambiguity; the other setters forward values directly since their types don't have that ambiguity. Re-verified the previously flagged registry.prune gap (WARNING above): still present, unrelated to lines touched by this diff.

Fix these issues in Kilo Cloud

Previous review (commit f6a1725)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx 1108 registry.prune (per-project tabs/tabMemory stores) is never called from pruneLive, so removed projects' tab state leaks for the life of the webview
Files Reviewed (incremental: 13 files since 2108dc5)

Reviewed the incremental diff against the previous review (2108dc5885d5dc2f71efe2a63bfe897d1ce581ae...f6a172535f246c7393a422f8579aa7865bfe422e).

  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx - consolidates per-project local tabs and per-context tab memory into one createProjectRegistry/createProjectStore pair, replacing the parallel tabs/tabMemory signals keyed ad hoc by memKey/tabKey. Renames memKey to nsKey and switches its project source from the catalog-fast activeProjectId to the applied currentProjectId, which now consistently matches the timing of selection()/registry.active(). Extracts project-state routing into createProjectStateRouter and target-remembering into createTargetRememberer. See WARNING above for a leak this introduces.
  • packages/kilo-vscode/webview-ui/agent-manager/project/registry.ts (new) - per-project store registry with legacy "single" bucket migration and a prune method; prune is unused by the caller (see WARNING).
  • packages/kilo-vscode/webview-ui/agent-manager/project/store.ts (new) - extracts createStoreTabs/createProjectStore (tabs + tabMemory) used by the registry; straightforward, no issues.
  • packages/kilo-vscode/webview-ui/agent-manager/project/state.ts (new) - extracts createProjectStateRouter, behavior-preserving move of the previous inline pending-state map/apply logic.
  • packages/kilo-vscode/webview-ui/agent-manager/project/selection.ts, project/live.ts, project/local-tabs.ts, project/restore.ts, project/sessions-live.ts - moved from flat project-*.ts filenames into a project/ directory with only import-path updates (or, for selection.ts, the pre-existing openTab-before-local ordering already tracked as an active comment) and local-tabs.ts losing its now-registry-owned bucketing logic; no new issues.
  • packages/kilo-vscode/webview-ui/agent-manager/selection-actions.ts - drops the now-unneeded memKey from SelectionActionDeps since tabMemory() is already scoped to the active project's store; consistent with the registry refactor.
  • Test files (agent-project-registry.test.ts rewritten against the new registry, agent-project-state-router.test.ts new, agent-local-tabs-store.test.ts deleted, agent-project-restore.test.ts/agent-project-selection-webview.test.ts import-path-only) - exercise real implementation without excessive mocking; adequate coverage of the new registry/router behavior.

Fix these issues in Kilo Cloud

Previous review (commit 2108dc5)

Status: 1 Issue Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 1
SUGGESTION 0
Issue Details (click to expand)

WARNING

File Line Issue
packages/kilo-vscode/webview-ui/agent-manager/project-selection.ts 30 openTab runs before deps.local, but buckets by currentProjectId, which can still lag the just-verified activeProjectId, misfiling the tab under the previous project
Files Reviewed (incremental: 3 files since ae28bad)

Reviewed the incremental diff against the previous review (ae28bad7...2108dc58, single PR commit 2108dc5885).

  • packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx - adds a pendingState map so a per-project agentManager.state push that arrives before the catalog marks that project active is deferred and applied once applyProjects sees it become active, instead of being silently dropped. This correctly reuses activeProjectId() (not the lagging currentProjectId()) as the trigger. Also wires a new openTab callback for applyProjectSelection. See WARNING above.
  • packages/kilo-vscode/webview-ui/agent-manager/project-selection.ts - adds openTab to the applyProjectSelection deps and calls it for unassigned sessions before deps.local/deps.session, to mirror legacy sidebar behavior of joining local tabs. See WARNING above for a bucketing race this introduces.
  • packages/kilo-vscode/tests/unit/agent-project-selection-webview.test.ts - only extends the stub deps object with a no-op openTab; no new test exercises the unassigned-session/openTab branch or the ordering relative to currentProjectId.

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 (8093fedf...ae28bad7, PR-authored commits 827b61dee1 + ae28bad7a8; the range also contains unrelated merge commits pulling in main, excluded from review since they aren't part of this PR's changes).

  • `packages/kilo-vscode/webview-ui/agent-manager/project-selec

[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 main

marius-kilocode and others added 2 commits July 28, 2026 10:32
…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.
Comment thread packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
…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.
Comment thread packages/kilo-vscode/webview-ui/agent-manager/project/selection.ts
…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.
Comment thread packages/kilo-vscode/webview-ui/agent-manager/AgentManagerApp.tsx
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.
Comment thread packages/kilo-vscode/src/agent-manager/AgentManagerProvider.ts Outdated
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.
@marius-kilocode
marius-kilocode merged commit 166d04e into main Jul 30, 2026
34 checks passed
@marius-kilocode
marius-kilocode deleted the abalone-bactrosaurus branch July 30, 2026 16:07
t7tran pushed a commit to t7tran/kilocode that referenced this pull request Aug 14, 2026
feat(vscode): multi-project Agent Manager
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants