diff --git a/packages/tui/src/feature-plugins/system/storybook/session-location-missing.tsx b/packages/tui/src/feature-plugins/system/storybook/session-location-missing.tsx
index ac87602bfa7..75ef4cb9ddf 100644
--- a/packages/tui/src/feature-plugins/system/storybook/session-location-missing.tsx
+++ b/packages/tui/src/feature-plugins/system/storybook/session-location-missing.tsx
@@ -1,18 +1,17 @@
import type { Plugin } from "@opencode-ai/plugin/tui"
import { useTerminalDimensions } from "@opentui/solid"
import { TextAttributes } from "@opentui/core"
-import { createSignal, For, Show } from "solid-js"
+import { createSignal } from "solid-js"
+import { SessionLocationMissing } from "../../../routes/session/location-missing"
import type { Story } from "./index"
import { StoryFooter } from "./footer"
-const missing = "~/code/open-source/opencode-workerd-profile"
-const destinations = ["~/code/open-source/opencode", "~/code/open-source/opencode-instruction-rename"]
+const directory = "/Users/kit/code/open-source/opencode-workerd-profile"
function SessionLocationMissingStory(props: { context: Plugin.Context }) {
const dimensions = useTerminalDimensions()
const theme = props.context.theme.contextual.elevated
- const [state, setState] = createSignal<"missing" | "move" | "recovered">("missing")
- const [selected, setSelected] = createSignal(0)
+ const [message, setMessage] = createSignal("Select a recovery action")
props.context.keymap.layer(() => ({
commands: [
@@ -22,43 +21,15 @@ function SessionLocationMissingStory(props: { context: Plugin.Context }) {
group: "Storybook",
run: () => props.context.ui.router.navigate({ type: "plugin", name: "storybook" }),
},
- {
- bind: "return",
- title: "Continue",
- group: "Storybook",
- run: () => {
- if (state() === "missing") return setState("move")
- if (state() === "move") return setState("recovered")
- },
- },
- {
- bind: "up,k",
- title: "Previous destination",
- group: "Storybook",
- run: () => state() === "move" && setSelected((current) => (current + destinations.length - 1) % destinations.length),
- },
- {
- bind: "down,j",
- title: "Next destination",
- group: "Storybook",
- run: () => state() === "move" && setSelected((current) => (current + 1) % destinations.length),
- },
- {
- bind: "r",
- title: "Reset story",
- group: "Storybook",
- run: () => {
- setSelected(0)
- setState("missing")
- },
- },
],
}))
return (
- Workerd Modal workspace driver
+
+ Workerd Modal workspace driver
+
build · GPT-5.6 Sol (high)
You
@@ -67,47 +38,15 @@ function SessionLocationMissingStory(props: { context: Plugin.Context }) {
Build · GPT-5.6 Sol (high)
The deployment is verified and the worktree is clean.
-
-
-
- Session directory no longer exists
-
- {missing}
- Move this session to continue.
- [ Move session ] [ Copy path ]
-
-
-
-
- Move session
- Choose a project directory
-
- {(directory, index) => (
-
- {index() === selected() ? "› " : " "}{directory}
-
- )}
-
-
-
-
-
- Session moved
- {destinations[selected()]}
-
- Ask anything...
-
-
-
+ setMessage("Move session requested")} />
diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx
index 154030ce9e7..fa986756902 100644
--- a/packages/tui/src/routes/session/index.tsx
+++ b/packages/tui/src/routes/session/index.tsx
@@ -109,7 +109,7 @@ import type { SessionInbox } from "@opencode-ai/schema/session-inbox"
import { generateThinkingSyntax } from "./thinking-syntax"
import { createDelayedPresence } from "../../util/delayed-presence"
import { usePromptMove } from "../../component/prompt/move"
-import { abbreviateHome } from "../../util/path-format"
+import { SessionLocationMissing } from "./location-missing"
addDefaultParsers(parsers.parsers)
@@ -1169,52 +1169,6 @@ export function Session() {
)
}
-function SessionLocationMissing(props: { directory: string; onMove: () => void }) {
- const theme = useTheme()
- const paths = useTuiPaths()
- const clipboard = useClipboard()
- const toast = useToast()
- const directory = createMemo(() => Locale.truncateMiddle(abbreviateHome(props.directory, paths.home), 72))
-
- return (
-
-
- Session directory no longer exists
-
- {directory()}
- Move this session to continue.
-
-
- Move session
-
- {
- void clipboard.write(props.directory)
- toast.show({ message: "Copied session directory", variant: "success" })
- }}
- >
- Copy path
-
-
-
- )
-}
-
type SessionRowViewProps = {
row: SessionRow
message: (messageID: string) => SessionMessageInfo | undefined
diff --git a/packages/tui/src/routes/session/location-missing.tsx b/packages/tui/src/routes/session/location-missing.tsx
new file mode 100644
index 00000000000..15b3811bc1c
--- /dev/null
+++ b/packages/tui/src/routes/session/location-missing.tsx
@@ -0,0 +1,38 @@
+import { createMemo } from "solid-js"
+import { useClipboard } from "../../context/clipboard"
+import { useTuiPaths } from "../../context/runtime"
+import { useTheme } from "../../context/theme"
+import { useToast } from "../../ui/toast"
+import { Locale } from "../../util/locale"
+import { abbreviateHome } from "../../util/path-format"
+import { SessionQuestion } from "./permission"
+
+export function SessionLocationMissing(props: { directory: string; onMove: () => void }) {
+ const paths = useTuiPaths()
+ const clipboard = useClipboard()
+ const toast = useToast()
+ const theme = useTheme("elevated")
+ const directory = createMemo(() => Locale.truncateMiddle(abbreviateHome(props.directory, paths.home), 72))
+
+ return (
+
+ {directory()}
+ Move this session to continue.
+
+ }
+ options={{ move: "Move session", copy: "Copy path" }}
+ onSelect={(option) => {
+ if (option === "move") return props.onMove()
+ void clipboard.write(props.directory)
+ toast.show({ message: "Copied session directory", variant: "success" })
+ }}
+ />
+ )
+}
diff --git a/packages/tui/src/routes/session/permission.tsx b/packages/tui/src/routes/session/permission.tsx
index 149a1c7753e..26253e870f5 100644
--- a/packages/tui/src/routes/session/permission.tsx
+++ b/packages/tui/src/routes/session/permission.tsx
@@ -141,7 +141,7 @@ export function PermissionPrompt(props: { request: PermissionRequest; directory?
return (
- >(props: {
+export function SessionQuestion>(props: {
title: string
semanticLabel?: string
instance: string
+ id?: string
+ group?: string
+ choicesLabel?: string
header?: JSX.Element
body: JSX.Element
options: T
@@ -431,6 +434,8 @@ function Prompt>(props: {
})
const narrow = createMemo(() => dimensions().width < 80)
const shortcuts = Keymap.useShortcuts()
+ const id = () => props.id ?? "session.permission"
+ const group = () => props.group ?? "Permission"
Keymap.createLayer(() => ({
mode: "base",
@@ -438,7 +443,7 @@ function Prompt>(props: {
{
id: "app.exit",
title: "Reject permission",
- group: "Permission",
+ group: group(),
bind: false,
run() {
if (!props.escapeKey) return
@@ -448,7 +453,7 @@ function Prompt>(props: {
{
id: "permission.prompt.fullscreen",
title: "Toggle permission fullscreen",
- group: "Permission",
+ group: group(),
bind: false,
run() {
if (!props.fullscreen) return
@@ -457,8 +462,8 @@ function Prompt>(props: {
},
{
bind: "left",
- title: "Previous permission option",
- group: "Permission",
+ title: "Previous option",
+ group: group(),
run: () => {
const idx = keys.indexOf(store.selected)
const next = keys[(idx - 1 + keys.length) % keys.length]
@@ -467,8 +472,8 @@ function Prompt>(props: {
},
{
bind: "h",
- title: "Previous permission option",
- group: "Permission",
+ title: "Previous option",
+ group: group(),
run: () => {
const idx = keys.indexOf(store.selected)
const next = keys[(idx - 1 + keys.length) % keys.length]
@@ -477,8 +482,8 @@ function Prompt>(props: {
},
{
bind: "right",
- title: "Next permission option",
- group: "Permission",
+ title: "Next option",
+ group: group(),
run: () => {
const idx = keys.indexOf(store.selected)
const next = keys[(idx + 1) % keys.length]
@@ -487,8 +492,8 @@ function Prompt>(props: {
},
{
bind: "l",
- title: "Next permission option",
- group: "Permission",
+ title: "Next option",
+ group: group(),
run: () => {
const idx = keys.indexOf(store.selected)
const next = keys[(idx + 1) % keys.length]
@@ -497,7 +502,7 @@ function Prompt>(props: {
},
{
bind: "return",
- title: "Select permission option",
+ title: "Select option",
group: "Permission",
run: () => props.onSelect(store.selected),
},
@@ -506,7 +511,7 @@ function Prompt>(props: {
{
bind: "escape",
title: "Reject permission",
- group: "Permission",
+ group: group(),
run: () => props.onSelect(props.escapeKey!),
},
]
@@ -520,7 +525,7 @@ function Prompt>(props: {
const content = () => (
({
instance: props.instance,
role: "dialog",
@@ -571,11 +576,11 @@ function Prompt>(props: {
alignItems={narrow() ? "flex-start" : "center"}
>
({
instance: props.instance,
role: "listbox",
- label: "Permission choices",
+ label: props.choicesLabel ?? "Permission choices",
}))}
flexDirection="row"
gap={1}
@@ -584,7 +589,7 @@ function Prompt>(props: {
{(option) => (
({
instance: props.instance,
role: "option",