Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
6fed0b4
feat(tui): implement onMount logic to handle prompts passed in cli to…
OpeOginni Feb 20, 2026
79d44b2
refactor(session): added guards for the initial Prompt submission dur…
OpeOginni Apr 10, 2026
ae67137
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni May 2, 2026
97e3853
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni May 5, 2026
80299b6
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni May 5, 2026
43d001d
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni May 28, 2026
8ad21fe
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni Jun 4, 2026
8713871
fix(tui): prevent potential timing issue with auto prompt
OpeOginni Jun 4, 2026
a5a94df
fix(tui): prevent replaying startup prompts on home
OpeOginni Jun 4, 2026
9e04f40
fix(tui): guard autosubmit until session metadata loads
OpeOginni Jun 4, 2026
04a5bd6
revert globals.ts push
OpeOginni Jun 4, 2026
b3ddd64
refactor(tui): make use of signals for cli prompt args
OpeOginni Jun 5, 2026
ff332bd
Merge remote-tracking branch 'origin/dev' into fix/cli-prompt-to-spec…
OpeOginni Jun 8, 2026
452c492
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni Jun 10, 2026
39d5939
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni Jul 3, 2026
75305d5
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni Jul 6, 2026
204e127
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni Jul 7, 2026
803799d
Merge branch 'dev' into fix/cli-prompt-to-specific-session
OpeOginni Jul 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions packages/tui/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,16 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi
})

const args = useArgs()
const seedInitialPrompt = () => {
const prompt = args.consumePrompt()

return prompt
? {
prompt: { input: prompt, parts: [] },
autoSubmit: true,
}
: {}
}
onMount(() => {
batch(() => {
if (args.agent) local.agent.set(args.agent)
Expand All @@ -493,6 +503,7 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi
route.navigate({
type: "session",
sessionID: args.sessionID,
...seedInitialPrompt(),
})
}
})
Expand All @@ -510,13 +521,13 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi
if (args.fork) {
void sdk.client.session.fork({ sessionID: match }).then((result) => {
if (result.data?.id) {
route.navigate({ type: "session", sessionID: result.data.id })
route.navigate({ type: "session", sessionID: result.data.id, ...seedInitialPrompt() })
} else {
toast.show({ message: "Failed to fork session", variant: "error" })
}
})
} else {
route.navigate({ type: "session", sessionID: match })
route.navigate({ type: "session", sessionID: match, ...seedInitialPrompt() })
}
}
})
Expand All @@ -530,7 +541,7 @@ function App(props: { onSnapshot?: () => Promise<string[]>; pluginHost: TuiPlugi
forked = true
void sdk.client.session.fork({ sessionID: args.sessionID }).then((result) => {
if (result.data?.id) {
route.navigate({ type: "session", sessionID: result.data.id })
route.navigate({ type: "session", sessionID: result.data.id, ...seedInitialPrompt() })
} else {
toast.show({ message: "Failed to fork session", variant: "error" })
}
Expand Down
32 changes: 31 additions & 1 deletion packages/tui/src/context/args.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { createSignal } from "solid-js"
import { createSimpleContext } from "./helper"

export interface Args {
Expand All @@ -12,5 +13,34 @@ export interface Args {

export const { use: useArgs, provider: ArgsProvider } = createSimpleContext({
name: "Args",
init: (props: Args) => props,
init: (props: Args) => {
const [prompt, setPrompt] = createSignal(props.prompt)

return {
get model() {
return props.model
},
get agent() {
return props.agent
},
get prompt() {
return prompt()
},
get continue() {
return props.continue
},
get sessionID() {
return props.sessionID
},
get fork() {
return props.fork
},
consumePrompt() {
const value = prompt()
if (!value) return
setPrompt(undefined)
return value
},
}
},
})
9 changes: 5 additions & 4 deletions packages/tui/src/context/route.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createStore, reconcile } from "solid-js/store"
import { createSignal } from "solid-js"
import { createSimpleContext } from "./helper"
import type { PromptInfo } from "../prompt/history"
import { useTuiStartup } from "./runtime"
Expand All @@ -12,6 +12,7 @@ export type SessionRoute = {
type: "session"
sessionID: string
prompt?: PromptInfo
autoSubmit?: boolean
}

export type PluginRoute = {
Expand All @@ -26,16 +27,16 @@ export const { use: useRoute, provider: RouteProvider } = createSimpleContext({
name: "Route",
init: (props: { initialRoute?: Route }) => {
const startup = useTuiStartup()
const [store, setStore] = createStore<Route>(
const [data, setData] = createSignal<Route>(
props.initialRoute ?? initialRoute(startup.initialRoute) ?? { type: "home" },
)

return {
get data() {
return store
return data()
},
navigate(route: Route) {
setStore(reconcile(route))
setData(route)
},
}
},
Expand Down
21 changes: 13 additions & 8 deletions packages/tui/src/routes/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import { useTerminalDimensions } from "@opentui/solid"
import { useTuiConfig } from "../config"
import { HomeSessionDestinationProvider } from "./home/session-destination"

let once = false
const placeholder = {
normal: ["Fix a TODO in the codebase", "What is the tech stack of this project?", "Fix broken tests"],
shell: ["ls -la", "git status", "pwd"],
Expand All @@ -30,6 +29,8 @@ export function Home() {
const editor = useEditorContext()
const dimensions = useTerminalDimensions()
const tuiConfig = useTuiConfig()
const [argPrompt, setArgPrompt] = createSignal<string | undefined>()
const [seededPrompt, setSeededPrompt] = createSignal(false)
const promptMaxWidth = createMemo(() => {
const configured = tuiConfig.prompt?.max_width
if (configured === "auto") return Math.max(75, Math.floor(dimensions().width * 0.7))
Expand All @@ -44,15 +45,18 @@ export function Home() {
const bind = (r: PromptRef | undefined) => {
setRef(r)
promptRef.set(r)
if (once || !r) return
if (seededPrompt() || !r) return
if (route.prompt) {
r.set(route.prompt)
once = true
setSeededPrompt(true)
return
}
if (!args.prompt) return
r.set({ input: args.prompt, parts: [] })
once = true
if (args.continue || args.sessionID || args.fork) return
const input = args.consumePrompt()
if (!input) return
setArgPrompt(input)
setSeededPrompt(true)
r.set({ input, parts: [] })
}

// Wait for sync and model store to be ready before auto-submitting --prompt
Expand All @@ -61,8 +65,9 @@ export function Home() {
if (sent) return
if (!r) return
if (!sync.ready || !local.model.ready) return
if (!args.prompt) return
if (r.current.input !== args.prompt) return
const input = argPrompt()
if (!input) return
if (r.current.input !== input) return
sent = true
r.submit()
})
Expand Down
22 changes: 20 additions & 2 deletions packages/tui/src/routes/session/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ export function Session() {
const route = useRouteData("session")
const { navigate } = useRoute()
const sync = useSync()
const local = useLocal()
const event = useEvent()
const project = useProject()
const paths = useTuiPaths()
Expand Down Expand Up @@ -334,15 +335,34 @@ export function Session() {
})

let seeded = false
let submitted = false
let scroll: ScrollBoxRenderable
let prompt: PromptRef | undefined
const [promptSignal, setPromptSignal] = createSignal<PromptRef | undefined>()
const bind = (r: PromptRef | undefined) => {
prompt = r
setPromptSignal(r)
promptRef.set(r)
if (seeded || !route.prompt || !r) return
seeded = true
r.set(route.prompt)
}

// CLI prompts can be routed into an existing session before sync/model hydration finishes.
// Wait for those stores so the submission uses the right defaults, and only auto-submit if
// the prompt still matches the seeded value so user edits are not submitted unexpectedly.
createEffect(() => {
const r = promptSignal()
if (submitted) return
if (!r) return
if (!sync.ready || !local.model.ready) return
if (!route.autoSubmit || !route.prompt?.input) return
const target = session()
if (!target || target.parentID) return
if (r.current.input !== route.prompt.input) return
submitted = true
r.submit()
})
const keymap = useOpencodeKeymap()
const dialog = useDialog()
const renderer = useRenderer()
Expand Down Expand Up @@ -420,8 +440,6 @@ export function Session() {
}, 50)
}

const local = useLocal()

function enterChild(sessionID: string) {
navigate({
type: "session",
Expand Down
Loading