diff --git a/packages/opencode/src/cli/cmd/tui/app.tsx b/packages/opencode/src/cli/cmd/tui/app.tsx index 97c910a47d4..8ff06d2a50a 100644 --- a/packages/opencode/src/cli/cmd/tui/app.tsx +++ b/packages/opencode/src/cli/cmd/tui/app.tsx @@ -286,22 +286,22 @@ function App() { const args = useArgs() onMount(() => { batch(() => { - if (args.agent) local.agent.set(args.agent) - if (args.model) { - const { providerID, modelID } = Provider.parseModel(args.model) + if (args.data.agent) local.agent.set(args.data.agent) + if (args.data.model) { + const { providerID, modelID } = Provider.parseModel(args.data.model) if (!providerID || !modelID) return toast.show({ variant: "warning", - message: `Invalid model format: ${args.model}`, + message: `Invalid model format: ${args.data.model}`, duration: 3000, }) local.model.set({ providerID, modelID }, { recent: true }) } // Handle --session without --fork immediately (fork is handled in createEffect below) - if (args.sessionID && !args.fork) { + if (args.data.sessionID && !args.data.fork) { route.navigate({ type: "session", - sessionID: args.sessionID, + sessionID: args.data.sessionID, }) } }) @@ -310,13 +310,13 @@ function App() { let continued = false createEffect(() => { // When using -c, session list is loaded in blocking phase, so we can navigate at "partial" - if (continued || sync.status === "loading" || !args.continue) return + if (continued || sync.status === "loading" || !args.data.continue) return const match = sync.data.session .toSorted((a, b) => b.time.updated - a.time.updated) .find((x) => x.parentID === undefined)?.id if (match) { continued = true - if (args.fork) { + if (args.data.fork) { sdk.client.session.fork({ sessionID: match }).then((result) => { if (result.data?.id) { route.navigate({ type: "session", sessionID: result.data.id }) @@ -335,9 +335,9 @@ function App() { // to avoid a race where reconcile overwrites the newly forked session) let forked = false createEffect(() => { - if (forked || sync.status !== "complete" || !args.sessionID || !args.fork) return + if (forked || sync.status !== "complete" || !args.data.sessionID || !args.data.fork) return forked = true - sdk.client.session.fork({ sessionID: args.sessionID }).then((result) => { + sdk.client.session.fork({ sessionID: args.data.sessionID }).then((result) => { if (result.data?.id) { route.navigate({ type: "session", sessionID: result.data.id }) } else { diff --git a/packages/opencode/src/cli/cmd/tui/context/args.tsx b/packages/opencode/src/cli/cmd/tui/context/args.tsx index 8a229ffaba6..efa19b4620a 100644 --- a/packages/opencode/src/cli/cmd/tui/context/args.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/args.tsx @@ -1,3 +1,4 @@ +import { createStore } from "solid-js/store" import { createSimpleContext } from "./helper" export interface Args { @@ -11,5 +12,26 @@ export interface Args { export const { use: useArgs, provider: ArgsProvider } = createSimpleContext({ name: "Args", - init: (props: Args) => props, + init: (props: Args) => { + const [data, setData] = createStore({ + model: props.model, + agent: props.agent, + prompt: props.prompt, + continue: props.continue, + sessionID: props.sessionID, + fork: props.fork, + }) + + return { + get data() { + return data + }, + consumePrompt() { + const value = data.prompt + if (!value) return + setData("prompt", undefined) // clear the prompt from the args once used + return value + }, + } + }, }) diff --git a/packages/opencode/src/cli/cmd/tui/context/local.tsx b/packages/opencode/src/cli/cmd/tui/context/local.tsx index d93079f12a4..967c59c9dbb 100644 --- a/packages/opencode/src/cli/cmd/tui/context/local.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/local.tsx @@ -152,8 +152,8 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({ const args = useArgs() const fallbackModel = createMemo(() => { - if (args.model) { - const { providerID, modelID } = Provider.parseModel(args.model) + if (args.data.model) { + const { providerID, modelID } = Provider.parseModel(args.data.model) if (isModelValid({ providerID, modelID })) { return { providerID, diff --git a/packages/opencode/src/cli/cmd/tui/context/route.tsx b/packages/opencode/src/cli/cmd/tui/context/route.tsx index 358461921b2..b4dc87d4fe2 100644 --- a/packages/opencode/src/cli/cmd/tui/context/route.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/route.tsx @@ -1,4 +1,4 @@ -import { createStore } from "solid-js/store" +import { createSignal } from "solid-js" import { createSimpleContext } from "./helper" import type { PromptInfo } from "../component/prompt/history" @@ -18,7 +18,7 @@ export type Route = HomeRoute | SessionRoute export const { use: useRoute, provider: RouteProvider } = createSimpleContext({ name: "Route", init: () => { - const [store, setStore] = createStore( + const [data, setData] = createSignal( process.env["OPENCODE_ROUTE"] ? JSON.parse(process.env["OPENCODE_ROUTE"]) : { @@ -28,11 +28,11 @@ export const { use: useRoute, provider: RouteProvider } = createSimpleContext({ return { get data() { - return store + return data() }, navigate(route: Route) { console.log("navigate", route) - setStore(route) + setData(route) }, } }, diff --git a/packages/opencode/src/cli/cmd/tui/context/sync.tsx b/packages/opencode/src/cli/cmd/tui/context/sync.tsx index 269ed7ae0bd..2aef240d885 100644 --- a/packages/opencode/src/cli/cmd/tui/context/sync.tsx +++ b/packages/opencode/src/cli/cmd/tui/context/sync.tsx @@ -363,7 +363,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ providerListPromise, agentsPromise, configPromise, - ...(args.continue ? [sessionListPromise] : []), + ...(args.data.continue ? [sessionListPromise] : []), ] await Promise.all(blockingRequests) @@ -372,7 +372,7 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ const providerListResponse = providerListPromise.then((x) => x.data!) const agentsResponse = agentsPromise.then((x) => x.data ?? []) const configResponse = configPromise.then((x) => x.data!) - const sessionListResponse = args.continue ? sessionListPromise : undefined + const sessionListResponse = args.data.continue ? sessionListPromise : undefined return Promise.all([ providersResponse, @@ -401,7 +401,9 @@ export const { use: useSync, provider: SyncProvider } = createSimpleContext({ if (store.status !== "complete") setStore("status", "partial") // non-blocking Promise.all([ - ...(args.continue ? [] : [sessionListPromise.then((sessions) => setStore("session", reconcile(sessions)))]), + ...(args.data.continue + ? [] + : [sessionListPromise.then((sessions) => setStore("session", reconcile(sessions)))]), sdk.client.command.list().then((x) => setStore("command", reconcile(x.data ?? []))), sdk.client.lsp.status().then((x) => setStore("lsp", reconcile(x.data!))), sdk.client.mcp.status().then((x) => setStore("mcp", reconcile(x.data!))), diff --git a/packages/opencode/src/cli/cmd/tui/routes/home.tsx b/packages/opencode/src/cli/cmd/tui/routes/home.tsx index c011f6c6246..7cf3256689e 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/home.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/home.tsx @@ -15,9 +15,6 @@ import { Installation } from "@/installation" import { useKV } from "../context/kv" import { useCommandDialog } from "../component/dialog-command" -// TODO: what is the best way to do this? -let once = false - export function Home() { const sync = useSync() const kv = useKV() @@ -77,13 +74,11 @@ export function Home() { let prompt: PromptRef const args = useArgs() onMount(() => { - if (once) return + const argPrompt = args.consumePrompt() if (route.initialPrompt) { prompt.set(route.initialPrompt) - once = true - } else if (args.prompt) { - prompt.set({ input: args.prompt, parts: [] }) - once = true + } else if (argPrompt) { + prompt.set({ input: argPrompt, parts: [] }) prompt.submit() } })