diff --git a/packages/opencode/src/cli/cmd/run/runtime.ts b/packages/opencode/src/cli/cmd/run/runtime.ts index 882ff2e6c7..25c4d84f97 100644 --- a/packages/opencode/src/cli/cmd/run/runtime.ts +++ b/packages/opencode/src/cli/cmd/run/runtime.ts @@ -14,7 +14,7 @@ // 4. runs the prompt queue until the footer closes. import { createOpencodeClient } from "@opencode-ai/sdk/v2" import { Flag } from "@opencode-ai/core/flag/flag" -import { createRunDemo } from "./demo" +import type { createRunDemo } from "./demo" import { resolveDiffStyle, resolveFooterKeybinds, resolveModelInfo, resolveSessionInfo } from "./runtime.boot" import { createRuntimeLifecycle } from "./runtime.lifecycle" import { recordRunSpanError, setRunSpanAttributes, withRunSpan } from "./otel" @@ -135,6 +135,10 @@ function variantsFor(providers: RunProvider[], model: RunInput["model"]) { return Object.keys(providers.find((item) => item.id === model.providerID)?.models?.[model.modelID]?.variants ?? {}) } +async function createDemo(input: Parameters[0]) { + return (await import("./demo")).createRunDemo(input) +} + async function resolveExitTitle( ctx: BootContext, input: RunRuntimeInput, @@ -425,7 +429,7 @@ async function runInteractiveRuntime(input: RunRuntimeInput): Promise { if (input.demo) { await ensureSession() - state.demo = createRunDemo({ + state.demo = await createDemo({ footer, sessionID: state.sessionID, thinking: input.thinking, @@ -548,7 +552,7 @@ async function runInteractiveRuntime(input: RunRuntimeInput): Promise { state.history = [] includeFiles = true state.demo = input.demo - ? createRunDemo({ + ? await createDemo({ footer, sessionID: state.sessionID, thinking: input.thinking, diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx index 59378b8717..19c1783ba6 100644 --- a/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx +++ b/packages/opencode/src/cli/cmd/tui/routes/session/index.tsx @@ -1573,8 +1573,14 @@ function TextPart(props: { last: boolean; part: TextPart; message: AssistantMess let spaces = 0 let replaced = false let skipWhitespace = false - return chunks.map((chunk) => { + return chunks.flatMap((chunk) => { + const result: TextChunk[] = [] let next = "" + const flush = () => { + if (!next) return + result.push(next === chunk.text ? chunk : { ...chunk, text: next }) + next = "" + } for (const char of chunk.text) { if (skipWhitespace && (char === " " || char === "\t")) { skipWhitespace = false @@ -1587,7 +1593,8 @@ function TextPart(props: { last: boolean; part: TextPart; message: AssistantMess continue } if (lineStart && !replaced && char === ">") { - next += "│ " + flush() + result.push({ __isChunk: true, text: "│ ", fg: theme.textMuted, attributes: TextAttributes.NONE }) replaced = true skipWhitespace = true continue @@ -1602,7 +1609,8 @@ function TextPart(props: { last: boolean; part: TextPart; message: AssistantMess } lineStart = false } - return next === chunk.text ? chunk : { ...chunk, text: next } + flush() + return result }) } const trimCodeIndent = (value: string) => { diff --git a/packages/opencode/src/cli/cmd/tui/thread.ts b/packages/opencode/src/cli/cmd/tui/thread.ts index ee5b7d2bda..8ce611517b 100644 --- a/packages/opencode/src/cli/cmd/tui/thread.ts +++ b/packages/opencode/src/cli/cmd/tui/thread.ts @@ -142,6 +142,7 @@ export const TuiThreadCommand = cmd({ } const cwd = Filesystem.resolve(process.cwd()) const config = TuiConfig.get() + config.catch(() => {}) if (args.demo) { const { createTuiDemo } = await import("./demo")