import { beforeAll, beforeEach, describe, expect, mock, test } from "bun:test" import type { Prompt } from "@/context/prompt" let createPromptSubmit: typeof import("./submit").createPromptSubmit const createdClients: string[] = [] const createdSessions: string[] = [] const enabledAutoAccept: Array<{ sessionID: string; directory: string }> = [] const optimistic: Array<{ directory?: string sessionID?: string message: { agent: string model: { providerID: string; modelID: string } variant?: string } }> = [] const optimisticSeeded: boolean[] = [] const storedSessions: Record> = {} const promoted: Array<{ directory: string; sessionID: string }> = [] const sentShell: string[] = [] const syncedDirectories: string[] = [] let params: { id?: string } = {} let selected = "/repo/worktree-a" let variant: string | undefined const promptValue: Prompt = [{ type: "text", content: "ls", start: 0, end: 2 }] const clientFor = (directory: string) => { createdClients.push(directory) return { session: { create: async () => { createdSessions.push(directory) return { data: { id: `session-${createdSessions.length}`, title: `New session ${createdSessions.length}`, }, } }, shell: async () => { sentShell.push(directory) return { data: undefined } }, prompt: async () => ({ data: undefined }), promptAsync: async () => ({ data: undefined }), command: async () => ({ data: undefined }), abort: async () => ({ data: undefined }), }, worktree: { create: async () => ({ data: { directory: `${directory}/new` } }), }, } } beforeAll(async () => { const rootClient = clientFor("/repo/main") mock.module("@solidjs/router", () => ({ useNavigate: () => () => undefined, useParams: () => params, })) mock.module("@opencode-ai/sdk/v2/client", () => ({ createOpencodeClient: (input: { directory: string }) => { createdClients.push(input.directory) return clientFor(input.directory) }, })) mock.module("@opencode-ai/ui/toast", () => ({ showToast: () => 0, })) mock.module("@opencode-ai/util/encode", () => ({ base64Encode: (value: string) => value, })) mock.module("@/context/local", () => ({ useLocal: () => ({ model: { current: () => ({ id: "model", provider: { id: "provider" } }), variant: { current: () => variant }, }, agent: { current: () => ({ name: "agent" }), }, session: { promote(directory: string, sessionID: string) { promoted.push({ directory, sessionID }) }, }, }), })) mock.module("@/context/permission", () => ({ usePermission: () => ({ enableAutoAccept(sessionID: string, directory: string) { enabledAutoAccept.push({ sessionID, directory }) }, }), })) mock.module("@/context/prompt", () => ({ usePrompt: () => ({ current: () => promptValue, reset: () => undefined, set: () => undefined, context: { add: () => undefined, remove: () => undefined, items: () => [], }, }), })) mock.module("@/context/layout", () => ({ useLayout: () => ({ handoff: { setTabs: () => undefined, }, }), })) mock.module("@/context/sdk", () => ({ useSDK: () => { const sdk = { directory: "/repo/main", client: rootClient, url: "http://localhost:4096", createClient(opts: any) { return clientFor(opts.directory) }, } return sdk }, })) mock.module("@/context/sync", () => ({ useSync: () => ({ data: { command: [] }, session: { optimistic: { add: (value: { directory?: string sessionID?: string message: { agent: string; model: { providerID: string; modelID: string }; variant?: string } }) => { optimistic.push(value) optimisticSeeded.push( !!value.directory && !!value.sessionID && !!storedSessions[value.directory]?.find((item) => item.id === value.sessionID)?.title, ) }, remove: () => undefined, }, }, set: () => undefined, }), })) mock.module("@/context/global-sync", () => ({ useGlobalSync: () => ({ child: (directory: string) => { syncedDirectories.push(directory) storedSessions[directory] ??= [] return [ { session: storedSessions[directory] }, (...args: unknown[]) => { if (args[0] !== "session") return const next = args[1] if (typeof next === "function") { storedSessions[directory] = next(storedSessions[directory]) as Array<{ id: string; title?: string }> return } if (Array.isArray(next)) { storedSessions[directory] = next as Array<{ id: string; title?: string }> } }, ] }, }), })) mock.module("@/context/platform", () => ({ usePlatform: () => ({ fetch: fetch, }), })) mock.module("@/context/language", () => ({ useLanguage: () => ({ t: (key: string) => key, }), })) const mod = await import("./submit") createPromptSubmit = mod.createPromptSubmit }) beforeEach(() => { createdClients.length = 0 createdSessions.length = 0 enabledAutoAccept.length = 0 optimistic.length = 0 optimisticSeeded.length = 0 promoted.length = 0 params = {} sentShell.length = 0 syncedDirectories.length = 0 selected = "/repo/worktree-a" variant = undefined for (const key of Object.keys(storedSessions)) delete storedSessions[key] }) describe("prompt submit worktree selection", () => { test("reads the latest worktree accessor value per submit", async () => { const submit = createPromptSubmit({ info: () => undefined, imageAttachments: () => [], commentCount: () => 0, autoAccept: () => false, mode: () => "shell", working: () => false, editor: () => undefined, queueScroll: () => undefined, promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0), addToHistory: () => undefined, resetHistoryNavigation: () => undefined, setMode: () => undefined, setPopover: () => undefined, newSessionWorktree: () => selected, onNewSessionWorktreeReset: () => undefined, onSubmit: () => undefined, }) const event = { preventDefault: () => undefined } as unknown as Event await submit.handleSubmit(event) selected = "/repo/worktree-b" await submit.handleSubmit(event) expect(createdClients).toEqual(["/repo/worktree-a", "/repo/worktree-b"]) expect(createdSessions).toEqual(["/repo/worktree-a", "/repo/worktree-b"]) expect(sentShell).toEqual(["/repo/worktree-a", "/repo/worktree-b"]) expect(syncedDirectories).toEqual(["/repo/worktree-a", "/repo/worktree-a", "/repo/worktree-b", "/repo/worktree-b"]) expect(promoted).toEqual([ { directory: "/repo/worktree-a", sessionID: "session-1" }, { directory: "/repo/worktree-b", sessionID: "session-2" }, ]) expect(syncedDirectories).toEqual(["/repo/worktree-a", "/repo/worktree-a", "/repo/worktree-b", "/repo/worktree-b"]) }) test("applies auto-accept to newly created sessions", async () => { const submit = createPromptSubmit({ info: () => undefined, imageAttachments: () => [], commentCount: () => 0, autoAccept: () => true, mode: () => "shell", working: () => false, editor: () => undefined, queueScroll: () => undefined, promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0), addToHistory: () => undefined, resetHistoryNavigation: () => undefined, setMode: () => undefined, setPopover: () => undefined, newSessionWorktree: () => selected, onNewSessionWorktreeReset: () => undefined, onSubmit: () => undefined, }) const event = { preventDefault: () => undefined } as unknown as Event await submit.handleSubmit(event) expect(enabledAutoAccept).toEqual([{ sessionID: "session-1", directory: "/repo/worktree-a" }]) }) test("includes the selected variant on optimistic prompts", async () => { params = { id: "session-1" } variant = "high" const submit = createPromptSubmit({ info: () => ({ id: "session-1" }), imageAttachments: () => [], commentCount: () => 0, autoAccept: () => false, mode: () => "normal", working: () => false, editor: () => undefined, queueScroll: () => undefined, promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0), addToHistory: () => undefined, resetHistoryNavigation: () => undefined, setMode: () => undefined, setPopover: () => undefined, onSubmit: () => undefined, }) const event = { preventDefault: () => undefined } as unknown as Event await submit.handleSubmit(event) expect(optimistic).toHaveLength(1) expect(optimistic[0]).toMatchObject({ message: { agent: "agent", model: { providerID: "provider", modelID: "model" }, variant: "high", }, }) }) test("seeds new sessions before optimistic prompts are added", async () => { const submit = createPromptSubmit({ info: () => undefined, imageAttachments: () => [], commentCount: () => 0, autoAccept: () => false, mode: () => "normal", working: () => false, editor: () => undefined, queueScroll: () => undefined, promptLength: (value) => value.reduce((sum, part) => sum + ("content" in part ? part.content.length : 0), 0), addToHistory: () => undefined, resetHistoryNavigation: () => undefined, setMode: () => undefined, setPopover: () => undefined, newSessionWorktree: () => selected, onNewSessionWorktreeReset: () => undefined, onSubmit: () => undefined, }) const event = { preventDefault: () => undefined } as unknown as Event await submit.handleSubmit(event) expect(storedSessions["/repo/worktree-a"]).toEqual([{ id: "session-1", title: "New session 1" }]) expect(optimisticSeeded).toEqual([true]) }) })