diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 5b7f522534d..669a9929340 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -31,6 +31,7 @@ import { KVProvider, useKV } from "./context/kv" import { Provider } from "@/provider/provider" import { ArgsProvider, useArgs, type Args } from "./context/args" import open from "open" +import { PromptRefProvider, usePromptRef } from "./context/prompt" async function getTerminalBackgroundColor(): Promise<"dark" | "light"> { // can't set raw mode if not a TTY @@ -118,7 +119,9 @@ export function tui(input: { url: string; args: Args; onExit?: () => Promise - + + + @@ -159,6 +162,7 @@ function App() { const { theme, mode, setMode } = useTheme() const sync = useSync() const exit = useExit() + const promptRef = usePromptRef() createEffect(() => { console.log(JSON.stringify(route.data)) @@ -224,8 +228,12 @@ function App() { keybind: "session_new", category: "Session", onSelect: () => { + const current = promptRef.current + // Don't require focus - if there's any text, preserve it + const currentPrompt = current?.current?.input ? current.current : undefined route.navigate({ type: "home", + initialPrompt: currentPrompt, }) dialog.clear() }, diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx index 7271e2fc69e..840e2646b26 100644 --- a/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/component/prompt/index.tsx @@ -37,6 +37,7 @@ export type PromptProps = { export type PromptRef = { focused: boolean + current: PromptInfo set(prompt: PromptInfo): void reset(): void blur(): void @@ -377,6 +378,9 @@ export function Prompt(props: PromptProps) { get focused() { return input.focused }, + get current() { + return store.prompt + }, focus() { input.focus() }, diff --git a/packages/opencode/src/cli/cmd/tui/context/prompt.tsx b/packages/opencode/src/cli/cmd/tui/context/prompt.tsx new file mode 100644 index 00000000000..efbb050645e --- /dev/null +++ b/packages/opencode/src/cli/cmd/tui/context/prompt.tsx @@ -0,0 +1,18 @@ +import { createSimpleContext } from "./helper" +import type { PromptRef } from "../component/prompt" + +export const { use: usePromptRef, provider: PromptRefProvider } = createSimpleContext({ + name: "PromptRef", + init: () => { + let current: PromptRef | undefined + + return { + get current() { + return current + }, + set(ref: PromptRef | undefined) { + current = ref + }, + } + }, +}) diff --git a/packages/opencode/src/cli/cmd/tui/context/route.tsx b/packages/opencode/src/cli/cmd/tui/context/route.tsx index b906de99b38..22333a0589e 100644 --- a/packages/opencode/src/cli/cmd/tui/context/route.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/route.tsx @@ -1,8 +1,10 @@ import { createStore } from "solid-js/store" import { createSimpleContext } from "./helper" +import type { PromptInfo } from "../component/prompt/history" export type HomeRoute = { type: "home" + initialPrompt?: PromptInfo } export type SessionRoute = { diff --git a/packages/opencode/src/cli/cmd/tui/routes/home.tsx b/packages/opencode/src/cli/cmd/tui/routes/home.tsx index 33942c2a50b..df99eac885f 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/home.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/home.tsx @@ -1,15 +1,14 @@ import { Prompt, type PromptRef } from "@tui/component/prompt" -import { createMemo, Match, onMount, Show, Switch, type ParentProps } from "solid-js" +import { createMemo, Match, onMount, Show, Switch } from "solid-js" import { useTheme } from "@tui/context/theme" -import { useKeybind } from "../context/keybind" -import type { KeybindsConfig } from "@opencode-ai/sdk" import { Logo } from "../component/logo" import { Locale } from "@/util/locale" import { useSync } from "../context/sync" import { Toast } from "../ui/toast" import { useArgs } from "../context/args" -import { Global } from "@/global" import { useDirectory } from "../context/directory" +import { useRoute, useRouteData } from "@tui/context/route" +import { usePromptRef } from "../context/prompt" // TODO: what is the best way to do this? let once = false @@ -17,6 +16,8 @@ let once = false export function Home() { const sync = useSync() const { theme } = useTheme() + const route = useRouteData("home") + const promptRef = usePromptRef() const mcp = createMemo(() => Object.keys(sync.data.mcp).length > 0) const mcpError = createMemo(() => { return Object.values(sync.data.mcp).some((x) => x.status === "failed") @@ -45,7 +46,10 @@ export function Home() { const args = useArgs() onMount(() => { if (once) return - if (args.prompt) { + if (route.initialPrompt) { + prompt.set(route.initialPrompt) + once = true + } else if (args.prompt) { prompt.set({ input: args.prompt, parts: [] }) once = true } @@ -57,7 +61,13 @@ export function Home() { - (prompt = r)} hint={Hint} /> + { + prompt = r + promptRef.set(r) + }} + hint={Hint} + /> diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 9af2ce37873..3bbc1c95196 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -63,6 +63,7 @@ import { useKV } from "../../context/kv.tsx" import { Editor } from "../../util/editor" import stripAnsi from "strip-ansi" import { Footer } from "./footer.tsx" +import { usePromptRef } from "../../context/prompt" addDefaultParsers(parsers.parsers) @@ -98,6 +99,7 @@ export function Session() { const sync = useSync() const kv = useKV() const { theme } = useTheme() + const promptRef = usePromptRef() const session = createMemo(() => sync.session.get(route.sessionID)!) const messages = createMemo(() => sync.data.message[route.sessionID] ?? []) const permissions = createMemo(() => sync.data.permission[route.sessionID] ?? []) @@ -900,7 +902,10 @@ export function Session() { (prompt = r)} + ref={(r) => { + prompt = r + promptRef.set(r) + }} disabled={permissions().length > 0} onSubmit={() => { toBottom()