fix(agent-manager): extract pending-create below the app size cap

PR #12931 grew AgentManagerApp.tsx to 2808 lines, over its 2800
max-lines ESLint cap. Main's push workflows path-filter the lint job so
the breakage is latent there, but every kilo-vscode PR fails merge CI.
Extract the cross-project pending-create controller into
pending-create.ts instead of raising the cap.
This commit is contained in:
Josh Lambert
2026-08-06 09:49:22 -04:00
parent e5ae384ad9
commit d0dd908fb0
3 changed files with 50 additions and 23 deletions
@@ -5,6 +5,7 @@ import { join } from "node:path"
const root = join(__dirname, "..", "..")
const dialog = readFileSync(join(root, "webview-ui", "agent-manager", "NewWorktreeDialog.tsx"), "utf8")
const app = readFileSync(join(root, "webview-ui", "agent-manager", "AgentManagerApp.tsx"), "utf8")
const pending = readFileSync(join(root, "webview-ui", "agent-manager", "pending-create.ts"), "utf8")
const importer = readFileSync(join(root, "src", "agent-manager", "worktree-importer.ts"), "utf8")
const css = readFileSync(join(root, "webview-ui", "agent-manager", "agent-manager.css"), "utf8")
@@ -20,9 +21,10 @@ describe("Agent Manager New Worktree project targeting", () => {
})
it("does not replace a pending cross-project activation", () => {
expect(app).toContain("if (pendingCreate()) return")
expect(pending).toContain("if (pending()) return")
expect(app).toContain("usePendingCreate(activeProjectId")
expect(app).toContain('msg.type === "agentManager.importResult"')
expect(app).toContain("!msg.success && pendingCreate()?.projectId === msg.projectId")
expect(app).toContain("!msg.success) creation.abandon(msg.projectId)")
})
it("tags branch and import responses with their owning project", () => {
@@ -27,7 +27,6 @@ import type {
AgentManagerWorktreeDiffLoadingMessage,
AgentManagerWorktreeDiffNoticeMessage,
AgentManagerDiffBranchesMessage,
AgentManagerImportResultMessage,
AgentManagerApplyWorktreeDiffResultMessage,
AgentManagerWorktreeStatsMessage,
AgentManagerLocalStatsMessage,
@@ -181,6 +180,7 @@ import { clampPanelWidth, maxPanelWidth, minPanelWidth } from "./side-panel-layo
import { buildShortcutCategories } from "./shortcuts"
import { tracker } from "./telemetry"
import { createChatFocus, hasQuestionOption } from "./focus"
import { usePendingCreate } from "./pending-create"
import "./agent-manager.css"
import "./agent-manager-review.css"
import { cycleAgent as cycle } from "../src/context/session-agent"
@@ -268,12 +268,12 @@ const AgentManagerContent: Component = () => {
const [currentProjectId, setCurrentProjectId] = createSignal<string | undefined>()
const [projectStates, setProjectStates] = createSignal<Record<string, AgentManagerStateMessage>>({})
const activeProjectId = () => projectList().find((p) => p.active)?.id ?? currentProjectId()
const [pendingCreate, setPendingCreate] = createSignal<{ projectId: string }>()
const scheduleCreate = (projectId: string) => {
if (projectId === activeProjectId()) return
if (pendingCreate()) return
setPendingCreate({ projectId })
}
const creation = usePendingCreate(activeProjectId, (projectId, worktreeId) =>
vscode.postMessage({
type: "agentManager.activateSelection",
target: { projectId, kind: "worktree", worktreeId },
}),
)
const isActivePayload = (pid: string | undefined) =>
projectList().length === 0 || pid === undefined || pid === activeProjectId()
@@ -1394,15 +1394,7 @@ const AgentManagerContent: Component = () => {
if (msg.type === "agentManager.worktreeSetup") {
const ev = msg as AgentManagerWorktreeSetupMessage
const pending = pendingCreate()
if (ev.status === "ready" && ev.projectId && pending?.projectId === ev.projectId && ev.worktreeId) {
setPendingCreate(undefined)
vscode.postMessage({
type: "agentManager.activateSelection",
target: { projectId: ev.projectId, kind: "worktree", worktreeId: ev.worktreeId },
})
}
if (ev.status === "error" && pending?.projectId === ev.projectId) setPendingCreate(undefined)
creation.setup(ev)
const store = ev.projectId ? registry.ensure(ev.projectId) : registry.active()
const updateBusy: Setter<Map<string, WorktreeBusyState>> = (value) => store.setBusy(value)
if (ev.status === "ready" || ev.status === "error") {
@@ -1444,8 +1436,7 @@ const AgentManagerContent: Component = () => {
}
}
if (msg.type === "agentManager.importResult" && !msg.success && pendingCreate()?.projectId === msg.projectId)
setPendingCreate(undefined)
if (msg.type === "agentManager.importResult" && !msg.success) creation.abandon(msg.projectId)
if (msg.type === "agentManager.sessionAdded") {
const ev = msg as { type: string; sessionId: string; worktreeId: string }
@@ -1488,7 +1479,7 @@ const AgentManagerContent: Component = () => {
// When a multi-version progress update arrives, mark newly created worktrees as loading
if ((msg as { type: string }).type === "agentManager.multiVersionProgress") {
const ev = msg as unknown as AgentManagerMultiVersionProgressMessage
if (ev.status === "done" && pendingCreate()?.projectId === ev.projectId) setPendingCreate(undefined)
if (ev.status === "done") creation.abandon(ev.projectId)
if (ev.status === "done" && ev.groupId) {
// Clear busy state for all worktrees in this group
const store = ev.projectId ? registry.ensure(ev.projectId) : registry.active()
@@ -1914,7 +1905,7 @@ const AgentManagerContent: Component = () => {
projects={multiProject() ? projectList : undefined}
activeProjectId={activeProjectId()}
defaultBase={defaultBase}
onCreate={scheduleCreate}
onCreate={creation.schedule}
/>
))
}
@@ -2393,7 +2384,7 @@ const AgentManagerContent: Component = () => {
currentSessionID={session.currentSessionID}
mode={mode}
defaultBase={defaultBase}
onCreate={scheduleCreate}
onCreate={creation.schedule}
bindings={kb()}
t={t}
onSearchRef={(ref) => (sidebarSearchMenu = ref)}
@@ -0,0 +1,34 @@
import { createSignal } from "solid-js"
/**
* Tracks a cross-project worktree creation so the target project is activated
* once its worktree is ready, and abandons the pending activation when the
* creation fails or completes through another flow.
*/
export function usePendingCreate(
active: () => string | undefined,
activate: (projectId: string, worktreeId: string) => void,
) {
const [pending, setPending] = createSignal<{ projectId: string }>()
const schedule = (projectId: string) => {
if (projectId === active()) return
if (pending()) return
setPending({ projectId })
}
const abandon = (projectId?: string) => {
if (pending()?.projectId === projectId) setPending(undefined)
}
const setup = (ev: { status: string; projectId?: string; worktreeId?: string }) => {
if (pending()?.projectId !== ev.projectId) return
if (ev.status === "ready" && ev.projectId && ev.worktreeId) {
setPending(undefined)
activate(ev.projectId, ev.worktreeId)
}
if (ev.status === "error") setPending(undefined)
}
return { schedule, abandon, setup }
}