|
|
@@ -48,6 +48,7 @@ import type { SkillTool } from "@/tool/skill"
|
|
|
import { useKeyboard, useRenderer, useTerminalDimensions, type JSX } from "@opentui/solid"
|
|
|
import { useSDK } from "@tui/context/sdk"
|
|
|
import { useCommandDialog } from "@tui/component/dialog-command"
|
|
|
+import type { DialogContext } from "@tui/ui/dialog"
|
|
|
import { useKeybind } from "@tui/context/keybind"
|
|
|
import { Header } from "./header"
|
|
|
import { parsePatch } from "diff"
|
|
|
@@ -226,6 +227,8 @@ export function Session() {
|
|
|
let scroll: ScrollBoxRenderable
|
|
|
let prompt: PromptRef
|
|
|
const keybind = useKeybind()
|
|
|
+ const dialog = useDialog()
|
|
|
+ const renderer = useRenderer()
|
|
|
|
|
|
// Allow exit when in child session (prompt is hidden)
|
|
|
const exit = useExit()
|
|
|
@@ -312,19 +315,40 @@ export function Session() {
|
|
|
|
|
|
const local = useLocal()
|
|
|
|
|
|
+ function moveFirstChild() {
|
|
|
+ if (children().length === 1) return
|
|
|
+ const next = children().find((x) => !!x.parentID)
|
|
|
+ if (next) {
|
|
|
+ navigate({
|
|
|
+ type: "session",
|
|
|
+ sessionID: next.id,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
function moveChild(direction: number) {
|
|
|
if (children().length === 1) return
|
|
|
- let next = children().findIndex((x) => x.id === session()?.id) + direction
|
|
|
- if (next >= children().length) next = 0
|
|
|
- if (next < 0) next = children().length - 1
|
|
|
- if (children()[next]) {
|
|
|
+
|
|
|
+ const sessions = children().filter((x) => !!x.parentID)
|
|
|
+ let next = sessions.findIndex((x) => x.id === session()?.id) + direction
|
|
|
+
|
|
|
+ if (next >= sessions.length) next = 0
|
|
|
+ if (next < 0) next = sessions.length - 1
|
|
|
+ if (sessions[next]) {
|
|
|
navigate({
|
|
|
type: "session",
|
|
|
- sessionID: children()[next].id,
|
|
|
+ sessionID: sessions[next].id,
|
|
|
})
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ function childSessionHandler(func: (dialog: DialogContext) => void) {
|
|
|
+ return (dialog: DialogContext) => {
|
|
|
+ if (!session()?.parentID || dialog.stack.length > 0) return
|
|
|
+ func(dialog)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
const command = useCommandDialog()
|
|
|
command.register(() => [
|
|
|
{
|
|
|
@@ -884,24 +908,13 @@ export function Session() {
|
|
|
},
|
|
|
},
|
|
|
{
|
|
|
- title: "Next child session",
|
|
|
- value: "session.child.next",
|
|
|
- keybind: "session_child_cycle",
|
|
|
- category: "Session",
|
|
|
- hidden: true,
|
|
|
- onSelect: (dialog) => {
|
|
|
- moveChild(1)
|
|
|
- dialog.clear()
|
|
|
- },
|
|
|
- },
|
|
|
- {
|
|
|
- title: "Previous child session",
|
|
|
- value: "session.child.previous",
|
|
|
- keybind: "session_child_cycle_reverse",
|
|
|
+ title: "Go to child session",
|
|
|
+ value: "session.child.first",
|
|
|
+ keybind: "session_child_first",
|
|
|
category: "Session",
|
|
|
hidden: true,
|
|
|
onSelect: (dialog) => {
|
|
|
- moveChild(-1)
|
|
|
+ moveFirstChild()
|
|
|
dialog.clear()
|
|
|
},
|
|
|
},
|
|
|
@@ -911,7 +924,7 @@ export function Session() {
|
|
|
keybind: "session_parent",
|
|
|
category: "Session",
|
|
|
hidden: true,
|
|
|
- onSelect: (dialog) => {
|
|
|
+ onSelect: childSessionHandler((dialog) => {
|
|
|
const parentID = session()?.parentID
|
|
|
if (parentID) {
|
|
|
navigate({
|
|
|
@@ -920,7 +933,29 @@ export function Session() {
|
|
|
})
|
|
|
}
|
|
|
dialog.clear()
|
|
|
- },
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "Next child session",
|
|
|
+ value: "session.child.next",
|
|
|
+ keybind: "session_child_cycle",
|
|
|
+ category: "Session",
|
|
|
+ hidden: true,
|
|
|
+ onSelect: childSessionHandler((dialog) => {
|
|
|
+ moveChild(1)
|
|
|
+ dialog.clear()
|
|
|
+ }),
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "Previous child session",
|
|
|
+ value: "session.child.previous",
|
|
|
+ keybind: "session_child_cycle_reverse",
|
|
|
+ category: "Session",
|
|
|
+ hidden: true,
|
|
|
+ onSelect: childSessionHandler((dialog) => {
|
|
|
+ moveChild(-1)
|
|
|
+ dialog.clear()
|
|
|
+ }),
|
|
|
},
|
|
|
])
|
|
|
|
|
|
@@ -971,9 +1006,6 @@ export function Session() {
|
|
|
}
|
|
|
})
|
|
|
|
|
|
- const dialog = useDialog()
|
|
|
- const renderer = useRenderer()
|
|
|
-
|
|
|
// snap to bottom when session changes
|
|
|
createEffect(on(() => route.sessionID, toBottom))
|
|
|
|
|
|
@@ -1933,7 +1965,7 @@ function Task(props: ToolProps<typeof TaskTool>) {
|
|
|
</box>
|
|
|
<Show when={props.metadata.sessionId}>
|
|
|
<text fg={theme.text}>
|
|
|
- {keybind.print("session_child_cycle")}
|
|
|
+ {keybind.print("session_child_first")}
|
|
|
<span style={{ fg: theme.textMuted }}> view subagents</span>
|
|
|
</text>
|
|
|
</Show>
|