mirror of
https://github.com/Kilo-Org/kilocode.git
synced 2026-08-28 19:11:03 +08:00
refactor: fix app typecheck
This commit is contained in:
@@ -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) => {
|
||||
|
||||
Reference in New Issue
Block a user