refactor: fix app typecheck

This commit is contained in:
Catriel Müller
2026-04-12 15:30:51 -03:00
parent fd5992d318
commit 17c834bb53
3 changed files with 46 additions and 141 deletions
+1 -102
View File
@@ -1,4 +1,4 @@
import type { Project, UserMessage } from "@kilocode/sdk/v2"
import type { Project, UserMessage } from "@opencode-ai/sdk/v2"
import { useDialog } from "@opencode-ai/ui/context/dialog"
import { useMutation } from "@tanstack/solid-query"
import {
@@ -7,7 +7,6 @@ import {
Show,
Match,
Switch,
createRoot,
createMemo,
createEffect,
createComputed,
@@ -351,105 +350,6 @@ export default function Page() {
},
})
// kilocode_change start - handle mode switch from question options
let modeActionAbort: AbortController | undefined
const waitForIdle = (sessionID: string, signal: AbortSignal) =>
new Promise<void>((resolve, reject) => {
let settled = false
const ref: { dispose?: () => void } = {}
const settle = (fn: () => void) => {
if (settled) return
settled = true
clearTimeout(timeout)
ref.dispose?.()
fn()
}
const timeout = setTimeout(() => {
settle(() => reject(new Error("Timed out waiting for session idle")))
}, 30_000)
createRoot((dispose) => {
ref.dispose = dispose
signal.addEventListener("abort", () => settle(() => reject(new Error("Cancelled"))), { once: true })
createEffect(() => {
const status = sync.data.session_status[sessionID]
if (!status || status.type !== "idle") return
settle(() => resolve())
})
})
})
onCleanup(() => modeActionAbort?.abort())
const handleModeAction = async (input: { mode: string; text: string; description?: string }) => {
const sessionID = params.id
if (!sessionID) return
modeActionAbort?.abort()
const controller = new AbortController()
modeActionAbort = controller
const toastTimer = setTimeout(() => {
showToast({
title: language.t("session.modeSwitch.switching", { mode: input.mode }),
description: language.t("session.modeSwitch.waiting"),
})
}, 500)
try {
// Allow one microtask for session status to reflect the reply before checking idle
await new Promise((r) => setTimeout(r, 0))
await waitForIdle(sessionID, controller.signal)
} catch (err: unknown) {
clearTimeout(toastTimer)
if (controller.signal.aborted) return
const message = err instanceof Error ? err.message : String(err)
showToast({ title: language.t("common.requestFailed"), description: message })
return
}
clearTimeout(toastTimer)
if (controller.signal.aborted) return
local.agent.set(input.mode)
const agent = local.agent.current()
if (!agent) return
if (agent.name !== input.mode) {
showToast({
title: language.t("session.modeSwitch.notAvailable"),
description: language.t("session.modeSwitch.fallback", { requested: input.mode, actual: agent.name }),
})
}
const model = local.model.current()
if (!model) return
const variant = local.model.variant.current()
const messageID = Identifier.ascending("message")
sdk.client.session
.prompt({
sessionID,
agent: agent.name,
model: {
modelID: model.id,
providerID: model.provider.id,
},
messageID,
parts: [{ type: "text", text: input.description ?? input.text }],
variant,
})
.catch((err: unknown) => {
const message = err instanceof Error ? err.message : String(err)
showToast({ title: language.t("common.requestFailed"), description: message })
})
}
// kilocode_change end
const composer = createSessionComposerState()
const workspaceKey = createMemo(() => params.dir ?? "")
@@ -1941,7 +1841,6 @@ export default function Page() {
setPromptDockRef={(el) => {
promptDock = el
}}
onModeAction={handleModeAction} // kilocode_change
/>
<Show when={desktopReviewOpen()}>
@@ -41,7 +41,6 @@ export function SessionComposerRegion(props: {
onRestore: (id: string) => void
}
setPromptDockRef: (el: HTMLDivElement) => void
onModeAction?: (input: { mode: string; text: string; description?: string }) => void // kilocode_change
}) {
const prompt = usePrompt()
const language = useLanguage()
@@ -140,12 +139,7 @@ export function SessionComposerRegion(props: {
<Show when={props.state.questionRequest()} keyed>
{(request) => (
<div>
{/* kilocode_change: add onModeAction */}
<SessionQuestionDock
request={request}
onSubmit={props.onResponseSubmit}
onModeAction={props.onModeAction}
/>
<SessionQuestionDock request={request} onSubmit={props.onResponseSubmit} />
</div>
)}
</Show>
@@ -5,19 +5,54 @@ import { Button } from "@opencode-ai/ui/button"
import { DockPrompt } from "@opencode-ai/ui/dock-prompt"
import { Icon } from "@opencode-ai/ui/icon"
import { showToast } from "@opencode-ai/ui/toast"
import type { QuestionAnswer, QuestionRequest } from "@kilocode/sdk/v2"
import type { QuestionAnswer, QuestionRequest } from "@opencode-ai/sdk/v2"
import { useLanguage } from "@/context/language"
import { useSDK } from "@/context/sdk"
const cache = new Map<string, { tab: number; answers: QuestionAnswer[]; custom: string[]; customOn: boolean[] }>()
// kilocode_change start - add onModeAction prop for mode-switching support
export const SessionQuestionDock: Component<{
request: QuestionRequest
onSubmit: () => void
onModeAction?: (input: { mode: string; text: string; description?: string }) => void
}> = (props) => {
// kilocode_change end
function Mark(props: { multi: boolean; picked: boolean; onClick?: (event: MouseEvent) => void }) {
return (
<span data-slot="question-option-check" aria-hidden="true" onClick={props.onClick}>
<span data-slot="question-option-box" data-type={props.multi ? "checkbox" : "radio"} data-picked={props.picked}>
<Show when={props.multi} fallback={<span data-slot="question-option-radio-dot" />}>
<Icon name="check-small" size="small" />
</Show>
</span>
</span>
)
}
function Option(props: {
multi: boolean
picked: boolean
label: string
description?: string
disabled: boolean
onClick: VoidFunction
}) {
return (
<button
type="button"
data-slot="question-option"
data-picked={props.picked}
role={props.multi ? "checkbox" : "radio"}
aria-checked={props.picked}
disabled={props.disabled}
onClick={props.onClick}
>
<Mark multi={props.multi} picked={props.picked} />
<span data-slot="question-option-main">
<span data-slot="option-label">{props.label}</span>
<Show when={props.description}>
<span data-slot="option-description">{props.description}</span>
</Show>
</span>
</button>
)
}
export const SessionQuestionDock: Component<{ request: QuestionRequest; onSubmit: () => void }> = (props) => {
const sdk = useSDK()
const language = useLanguage()
@@ -181,33 +216,10 @@ export const SessionQuestionDock: Component<{
const picked = (answer: string) => store.answers[store.tab]?.includes(answer) ?? false
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) as
| (ReturnType<typeof options>[number] & { mode?: string })
| undefined
// kilocode_change end
setStore("editing", false)
setStore("answers", store.tab, [answer])
if (custom) setStore("custom", store.tab, answer)
if (!custom) setStore("customOn", store.tab, false)
// kilocode_change start - trigger mode switch after question reply completes
if (!multi()) {
const pending = reply([[answer]])
if (option?.mode && props.onModeAction) {
const action = props.onModeAction
const mode = option.mode
const description = option.description
pending?.then(() => action({ mode, text: answer, description }), fail).catch(fail)
} else {
pending?.catch(fail)
}
return
}
// kilocode_change end
setStore("editing", false)
}
const toggle = (answer: string) => {