diff --git a/packages/tui/src/routes/session/index.tsx b/packages/tui/src/routes/session/index.tsx
index c9eb7ed5fa13..67f727a9c87c 100644
--- a/packages/tui/src/routes/session/index.tsx
+++ b/packages/tui/src/routes/session/index.tsx
@@ -2819,10 +2819,15 @@ function Shell(props: ToolProps) {
})
const maxLines = 10
const maxChars = createMemo(() => maxLines * Math.max(20, ctx.width - 6))
+ const prompt = createMemo(() => (workdir() && workdir() !== "." ? `${workdir()}$` : "$"))
const input = createMemo(() => {
- if (!command()) return ""
- const prompt = workdir() && workdir() !== "." ? `${workdir()}$ ` : isRunning() ? "" : "$ "
- return `${prompt}${command()}`
+ const cmd = command()
+ if (!cmd) return ""
+ // While running, the workdir prompt shares the spinner's text column; when
+ // settled, the prompt renders as its own column so wrapped command lines
+ // keep a stable hanging indent instead of jumping to the card inset.
+ if (isRunning() && prompt() !== "$") return `${prompt()} ${cmd}`
+ return cmd
})
const content = createMemo(() => [input(), output()].filter(Boolean).join("\n\n"))
const collapsed = createMemo(() => collapseToolOutput(content(), maxLines, maxChars()))
@@ -2830,6 +2835,8 @@ function Shell(props: ToolProps) {
if (expanded() || !collapsed().overflow) return content()
return collapsed().output
})
+ const limitedInput = createMemo(() => limited().slice(0, input().length))
+ const limitedOutput = createMemo(() => limited().slice(Math.min(limited().length, input().length + 2)))
const expandable = createMemo(() => Boolean(shellID()) || collapsed().overflow)
const toggle = () => {
const next = !expanded()
@@ -2853,16 +2860,16 @@ function Shell(props: ToolProps) {
- {limited().slice(0, input().length)}
- {limited().slice(input().length)}
-
+
+ {prompt()}
+ {limitedInput()}
+
}
>
-
- {limited().slice(0, input().length)}
- {limited().slice(input().length)}
-
+ {limitedInput()}
+
+
+ {limitedOutput()}