diff --git a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx
index 987f51571..21364d4a8 100644
--- a/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/dialog-command.tsx
@@ -56,7 +56,7 @@ export function CommandProvider(props: ParentProps) {
const dialog = useDialog()
useKeyboard((evt) => {
- if (evt.name === "k" && evt.ctrl) {
+ if (evt.name === "p" && evt.ctrl) {
dialog.replace(() => )
return
}
diff --git a/packages/opencode/src/cli/cmd/tui/component/prompt.tsx b/packages/opencode/src/cli/cmd/tui/component/prompt.tsx
index a4172ef33..ae4de24e6 100644
--- a/packages/opencode/src/cli/cmd/tui/component/prompt.tsx
+++ b/packages/opencode/src/cli/cmd/tui/component/prompt.tsx
@@ -207,7 +207,7 @@ export function Prompt(props: PromptProps) {
- ctrl+k commands
+ ctrl+p commands
@@ -421,7 +421,7 @@ function Autocomplete(props: {
return store.visible
},
onInput(value: string) {
- if (value.length <= store.index) hide()
+ if (store.visible && value.length <= store.index) hide()
},
onKeyDown(e: ParsedKey) {
if (store.visible) {
diff --git a/packages/opencode/src/cli/cmd/tui/session.tsx b/packages/opencode/src/cli/cmd/tui/session.tsx
index e284ff038..8605e11dc 100644
--- a/packages/opencode/src/cli/cmd/tui/session.tsx
+++ b/packages/opencode/src/cli/cmd/tui/session.tsx
@@ -138,13 +138,17 @@ export function Session() {
flexGrow={1}
>
- {(message) => (
+ {(message, index) => (
-
+
)}
@@ -193,7 +197,7 @@ function UserMessage(props: { message: UserMessage; parts: Part[] }) {
)
}
-function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) {
+function AssistantMessage(props: { message: AssistantMessage; parts: Part[]; last: boolean }) {
const local = useLocal()
return (
<>
@@ -221,7 +225,7 @@ function AssistantMessage(props: { message: AssistantMessage; parts: Part[] }) {
{props.message.error?.data.message}
-
+
1) {
+ if (previous.height > 1 || previous.marginTop === 1) {
el.marginTop = 1
return
}
diff --git a/packages/opencode/src/cli/cmd/tui/ui/shimmer.tsx b/packages/opencode/src/cli/cmd/tui/ui/shimmer.tsx
index 40e87951b..d6e38fc63 100644
--- a/packages/opencode/src/cli/cmd/tui/ui/shimmer.tsx
+++ b/packages/opencode/src/cli/cmd/tui/ui/shimmer.tsx
@@ -7,11 +7,11 @@ export type ShimmerProps = {
color: string
}
-const DURATION = 200
+const DURATION = 2_500
export function Shimmer(props: ShimmerProps) {
const timeline = createComponentTimeline({
- duration: (props.text.length + 1) * DURATION,
+ duration: DURATION,
loop: true,
})
const characters = props.text.split("")
@@ -23,12 +23,12 @@ export function Shimmer(props: ShimmerProps) {
{ shimmer: 0.4 },
{ shimmer: 1 },
{
- duration: DURATION,
+ duration: DURATION / (props.text.length + 1),
ease: "linear",
alternate: true,
loop: 2,
},
- (i * DURATION) / 2,
+ (i * (DURATION / (props.text.length + 1))) / 2,
),
)
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index 01c61e3f6..420eb104d 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -1008,12 +1008,6 @@ export namespace SessionPrompt {
throw value.error
case "start-step":
- await Session.updatePart({
- id: Identifier.ascending("part"),
- messageID: assistantMsg.id,
- sessionID: assistantMsg.sessionID,
- type: "step-start",
- })
snapshot = await Snapshot.track()
break
@@ -1021,14 +1015,6 @@ export namespace SessionPrompt {
const usage = Session.getUsage(input.model, value.usage, value.providerMetadata)
assistantMsg.cost += usage.cost
assistantMsg.tokens = usage.tokens
- await Session.updatePart({
- id: Identifier.ascending("part"),
- messageID: assistantMsg.id,
- sessionID: assistantMsg.sessionID,
- type: "step-finish",
- tokens: usage.tokens,
- cost: usage.cost,
- })
await Session.updateMessage(assistantMsg)
if (snapshot) {
const patch = await Snapshot.patch(snapshot)
@@ -1095,6 +1081,7 @@ export namespace SessionPrompt {
log.error("process", {
error: e,
})
+ assistantMsg.finish = "error"
switch (true) {
case e instanceof DOMException && e.name === "AbortError":
assistantMsg.error = new MessageV2.AbortedError(