From 8f579ac8e14f22033ee864403fd84f82140b3d9e Mon Sep 17 00:00:00 2001 From: Alex Alecu Date: Tue, 17 Feb 2026 16:17:45 +0200 Subject: [PATCH] fix(app): wrap waitForIdle reactive effect in createRoot for proper disposal --- packages/app/src/components/question-dock.tsx | 1 + packages/app/src/pages/session.tsx | 37 +++++++++++++------ 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/app/src/components/question-dock.tsx b/packages/app/src/components/question-dock.tsx index 0b091164181..68d569b60e9 100644 --- a/packages/app/src/components/question-dock.tsx +++ b/packages/app/src/components/question-dock.tsx @@ -66,6 +66,7 @@ export const QuestionDock: Component<{ const pick = (answer: string, custom: boolean = false) => { // kilocode_change start - find option to check for mode + // Custom answers won't match a predefined option, so mode switching is intentionally skipped const option = options().find((o) => o.label === answer) // kilocode_change end diff --git a/packages/app/src/pages/session.tsx b/packages/app/src/pages/session.tsx index d88f35f449d..b6f6affe2b1 100644 --- a/packages/app/src/pages/session.tsx +++ b/packages/app/src/pages/session.tsx @@ -1,4 +1,4 @@ -import { For, onCleanup, Show, Match, Switch, createMemo, createEffect, on } from "solid-js" +import { For, onCleanup, Show, Match, Switch, createMemo, createEffect, createRoot, on } from "solid-js" import { createMediaQuery } from "@solid-primitives/media" import { createResizeObserver } from "@solid-primitives/resize-observer" import { Dynamic } from "solid-js/web" @@ -157,17 +157,27 @@ export default function Page() { const waitForIdle = (sessionID: string, signal: AbortSignal) => new Promise((resolve, reject) => { - const timeout = setTimeout(() => reject(new Error("Timed out waiting for session idle")), 30_000) - signal.addEventListener("abort", () => { + let settled = false + const settle = (fn: () => void) => { + if (settled) return + settled = true clearTimeout(timeout) - reject(new Error("Cancelled")) - }) - createEffect(() => { - const status = sync.data.session_status[sessionID] - if (!status) return // not yet loaded — keep waiting - if (status.type !== "idle") return - clearTimeout(timeout) - resolve() + dispose() + fn() + } + const timeout = setTimeout(() => { + settle(() => reject(new Error("Timed out waiting for session idle"))) + }, 30_000) + + const dispose = createRoot((dispose) => { + signal.addEventListener("abort", () => settle(() => reject(new Error("Cancelled"))), { once: true }) + createEffect(() => { + const status = sync.data.session_status[sessionID] + if (!status) return // not yet loaded — keep waiting + if (status.type !== "idle") return + settle(() => resolve()) + }) + return dispose }) }) @@ -194,6 +204,9 @@ export default function Page() { local.agent.set(input.mode) + const agent = local.agent.current() + if (!agent) return + const model = local.model.current() if (!model) return @@ -203,7 +216,7 @@ export default function Page() { sdk.client.session .prompt({ sessionID, - agent: input.mode, + agent: agent.name, model: { modelID: model.id, providerID: model.provider.id,