diff --git a/.github/TEAM_MEMBERS b/.github/TEAM_MEMBERS deleted file mode 100644 index 22c9a923d33..00000000000 --- a/.github/TEAM_MEMBERS +++ /dev/null @@ -1,15 +0,0 @@ -adamdotdevin -Brendonovich -fwang -Hona -iamdavidhill -jayair -jlongster -kitlangton -kommander -MrMushrooooom -nexxeln -R44VC0RP -rekram1-node -RhysSullivan -thdxr diff --git a/packages/app/src/components/question-dock.tsx b/packages/app/src/components/question-dock.tsx deleted file mode 100644 index 9f0d7b1fd17..00000000000 --- a/packages/app/src/components/question-dock.tsx +++ /dev/null @@ -1,314 +0,0 @@ -import { For, Show, createMemo, type Component } from "solid-js" -import { createStore } from "solid-js/store" -import { Button } from "@opencode-ai/ui/button" -import { Icon } from "@opencode-ai/ui/icon" -import { showToast } from "@opencode-ai/ui/toast" -import type { QuestionAnswer, QuestionRequest } from "@kilocode/sdk/v2" -import { useLanguage } from "@/context/language" -import { useSDK } from "@/context/sdk" - -// kilocode_change start - add onModeAction prop for mode-switching support -export const QuestionDock: Component<{ - request: QuestionRequest - onModeAction?: (input: { mode: string; text: string; description?: string }) => void -}> = (props) => { - // kilocode_change end - const sdk = useSDK() - const language = useLanguage() - - const questions = createMemo(() => props.request.questions) - const single = createMemo(() => questions().length === 1 && questions()[0]?.multiple !== true) - - const [store, setStore] = createStore({ - tab: 0, - answers: [] as QuestionAnswer[], - custom: [] as string[], - editing: false, - sending: false, - }) - - const question = createMemo(() => questions()[store.tab]) - const confirm = createMemo(() => !single() && store.tab === questions().length) - const options = createMemo(() => question()?.options ?? []) - const input = createMemo(() => store.custom[store.tab] ?? "") - const multi = createMemo(() => question()?.multiple === true) - const customPicked = createMemo(() => { - const value = input() - if (!value) return false - return store.answers[store.tab]?.includes(value) ?? false - }) - - const fail = (err: unknown) => { - const message = err instanceof Error ? err.message : String(err) - showToast({ title: language.t("common.requestFailed"), description: message }) - } - - const reply = async (answers: QuestionAnswer[]) => { - if (store.sending) return - - setStore("sending", true) - try { - await sdk.client.question.reply({ requestID: props.request.id, answers }) - } catch (err) { - fail(err) - } finally { - setStore("sending", false) - } - } - - const reject = async () => { - if (store.sending) return - - setStore("sending", true) - try { - await sdk.client.question.reject({ requestID: props.request.id }) - } catch (err) { - fail(err) - } finally { - setStore("sending", false) - } - } - - const submit = () => { - void reply(questions().map((_, i) => store.answers[i] ?? []))?.catch(fail) // kilocode_change - } - - 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 - - setStore("answers", store.tab, [answer]) - - if (custom) { - setStore("custom", store.tab, answer) - } - - if (single()) { - // kilocode_change start - trigger mode switch after question reply completes - 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) - } - // kilocode_change end - return - } - - setStore("tab", store.tab + 1) - } - - const toggle = (answer: string) => { - setStore("answers", store.tab, (current = []) => { - if (current.includes(answer)) return current.filter((item) => item !== answer) - return [...current, answer] - }) - } - - const selectTab = (index: number) => { - setStore("tab", index) - setStore("editing", false) - } - - const selectOption = (optIndex: number) => { - if (store.sending) return - - if (optIndex === options().length) { - setStore("editing", true) - return - } - - const opt = options()[optIndex] - if (!opt) return - if (multi()) { - toggle(opt.label) - return - } - pick(opt.label) - } - - const handleCustomSubmit = (e: Event) => { - e.preventDefault() - if (store.sending) return - - const value = input().trim() - if (!value) { - setStore("editing", false) - return - } - - if (multi()) { - setStore("answers", store.tab, (current = []) => { - if (current.includes(value)) return current - return [...current, value] - }) - setStore("editing", false) - return - } - - pick(value, true) - setStore("editing", false) - } - - return ( -
- -
- - {(q, index) => { - const active = () => index() === store.tab - const answered = () => (store.answers[index()]?.length ?? 0) > 0 - return ( - - ) - }} - - -
-
- - -
-
- {question()?.question} - {multi() ? " " + language.t("ui.question.multiHint") : ""} -
-
- - {(opt, i) => { - const picked = () => store.answers[store.tab]?.includes(opt.label) ?? false - return ( - - ) - }} - - - -
- setTimeout(() => el.focus(), 0)} - type="text" - data-slot="custom-input" - placeholder={language.t("ui.question.custom.placeholder")} - value={input()} - disabled={store.sending} - onInput={(e) => { - setStore("custom", store.tab, e.currentTarget.value) - }} - /> - - -
-
-
-
-
- - -
-
{language.t("ui.messagePart.review.title")}
- - {(q, index) => { - const value = () => store.answers[index()]?.join(", ") ?? "" - const answered = () => Boolean(value()) - return ( -
- {q.question} - - {answered() ? value() : language.t("ui.question.review.notAnswered")} - -
- ) - }} -
-
-
- -
- - - - - - - - - -
-
- ) -} diff --git a/packages/app/src/pages/session/session-prompt-dock.test.ts b/packages/app/src/pages/session/session-prompt-dock.test.ts deleted file mode 100644 index b3a9945d66c..00000000000 --- a/packages/app/src/pages/session/session-prompt-dock.test.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { describe, expect, test } from "bun:test" -import { questionSubtitle } from "./session-prompt-helpers" - -describe("questionSubtitle", () => { - const t = (key: string) => { - if (key === "ui.common.question.one") return "question" - if (key === "ui.common.question.other") return "questions" - return key - } - - test("returns empty for zero", () => { - expect(questionSubtitle(0, t)).toBe("") - }) - - test("uses singular label", () => { - expect(questionSubtitle(1, t)).toBe("1 question") - }) - - test("uses plural label", () => { - expect(questionSubtitle(3, t)).toBe("3 questions") - }) -}) diff --git a/packages/app/src/pages/session/session-prompt-dock.tsx b/packages/app/src/pages/session/session-prompt-dock.tsx deleted file mode 100644 index f6029c10c00..00000000000 --- a/packages/app/src/pages/session/session-prompt-dock.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { For, Show } from "solid-js" -import type { QuestionRequest } from "@kilocode/sdk/v2" -import { Button } from "@opencode-ai/ui/button" -import { BasicTool } from "@opencode-ai/ui/basic-tool" -import { PromptInput } from "@/components/prompt-input" -import { QuestionDock } from "@/components/question-dock" -import { questionSubtitle } from "@/pages/session/session-prompt-helpers" - -export function SessionPromptDock(props: { - centered: boolean - questionRequest: () => QuestionRequest | undefined - permissionRequest: () => { patterns: string[]; permission: string } | undefined - blocked: boolean - promptReady: boolean - handoffPrompt?: string - t: (key: string, vars?: Record) => string - responding: boolean - onDecide: (response: "once" | "always" | "reject") => void - inputRef: (el: HTMLDivElement) => void - newSessionWorktree: string - onNewSessionWorktreeReset: () => void - onSubmit: () => void - setPromptDockRef: (el: HTMLDivElement) => void - onModeAction?: (input: { mode: string; text: string; description?: string }) => void // kilocode_change -}) { - return ( -
-
- - {(req) => { - const subtitle = questionSubtitle(req.questions.length, (key) => props.t(key)) - return ( -
- - {/* kilocode_change: add onModeAction */} - -
- ) - }} -
- - - {(perm) => ( -
- - 0}> -
- - {(pattern) => {pattern}} - -
-
- -
- {props.t("settings.permissions.tool.doom_loop.description")} -
-
-
-
-
- - - -
-
-
- )} -
- - - - {props.handoffPrompt || props.t("prompt.loading")} -
- } - > - - - -
- - ) -} diff --git a/packages/app/src/pages/session/session-prompt-helpers.ts b/packages/app/src/pages/session/session-prompt-helpers.ts deleted file mode 100644 index ac3234c939a..00000000000 --- a/packages/app/src/pages/session/session-prompt-helpers.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const questionSubtitle = (count: number, t: (key: string) => string) => { - if (count === 0) return "" - return `${count} ${t(count > 1 ? "ui.common.question.other" : "ui.common.question.one")}` -}