diff --git a/CHANGELOG.md b/CHANGELOG.md index 21993fe..b5556aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [7.0.6] - 2026-10-23 + +### Fixed + +- **The end of tool output no longer hides under the input box on Windows.** Files and command output with CRLF line endings rendered each `\r` as an extra line break, so diffs and previews (e.g. JSON edits) drew roughly twice as tall as the `\n`-based height estimates and the transcript's live edge slid beneath the composer, most visibly in full-screen terminals. Transcript rows, streaming text/reasoning, and approval diffs are now normalized to `\n` before rendering (`normalizeLineEndings` / `normalizeRow` in `src/ui/components/rows.tsx`), which also removes the doubled line spacing in those views. + ## [7.0.5] - 2026-10-14 ### Changed diff --git a/package-lock.json b/package-lock.json index b8f47c8..d363943 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@matterailab/orbcode", - "version": "7.0.5", + "version": "7.0.6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@matterailab/orbcode", - "version": "7.0.5", + "version": "7.0.6", "license": "MIT", "dependencies": { "@ai-sdk/anthropic": "^3.0.85", diff --git a/package.json b/package.json index 16787d8..ea83807 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@matterailab/orbcode", - "version": "7.0.5", + "version": "7.0.6", "description": "OrbCode CLI — agentic coding in your terminal, by MatterAI", "type": "module", "bin": { diff --git a/src/ui/App.tsx b/src/ui/App.tsx index 564a822..7575a93 100644 --- a/src/ui/App.tsx +++ b/src/ui/App.tsx @@ -117,6 +117,8 @@ import { } from "../core/resumeCost.js"; import { appendRow, + normalizeLineEndings, + normalizeRow, diffViewHeight, formatToolName, formatUserBlock, @@ -793,7 +795,11 @@ export function App({ const pushRow = useCallback((row: DistributiveOmit) => { setRows((prev) => - appendRow(prev, { ...row, id: rowId() } as Row, expandToolsRef.current), + appendRow( + prev, + { ...normalizeRow(row), id: rowId() } as Row, + expandToolsRef.current, + ), ); }, []); @@ -819,7 +825,7 @@ export function App({ case "reasoning-delta": countStreamedChars(event.text.length); reasoningBufferRef.current += event.text; - setStreamingReasoning(reasoningBufferRef.current); + setStreamingReasoning(normalizeLineEndings(reasoningBufferRef.current)); setBusyLabel("Thinking"); break; case "reasoning-done": @@ -832,7 +838,7 @@ export function App({ case "text-delta": countStreamedChars(event.text.length); textBufferRef.current += event.text; - setStreamingText(textBufferRef.current); + setStreamingText(normalizeLineEndings(textBufferRef.current)); setBusyLabel("Working"); break; case "text-done": @@ -986,7 +992,10 @@ export function App({ isStale() ? Promise.resolve("no") : new Promise((resolve) => - setPendingApproval({ request, resolve }), + setPendingApproval({ + request: normalizeRow(request), + resolve, + }), ), requestFollowup: (question, suggestions) => isStale() diff --git a/src/ui/components/rows.tsx b/src/ui/components/rows.tsx index c981109..a464311 100644 --- a/src/ui/components/rows.tsx +++ b/src/ui/components/rows.tsx @@ -51,6 +51,24 @@ export function isGroupableTool(row: { name: string; summary: string; isError: b return (row.name === "Bash" || row.name === "execute_command") && isReadOnlyCommand(row.summary) } +/** + * Windows tools emit CRLF. OpenTUI renders a bare \r as its own line break, so + * unnormalized text draws taller than the \n-based height estimates and the + * transcript's live edge slides under the composer. + */ +export function normalizeLineEndings(text: string): string { + return text.includes("\r") ? text.replace(/\r\n?/g, "\n") : text +} + +/** Normalize line endings in every string field of a row. */ +export function normalizeRow(row: T): T { + const out = { ...row } as Record + for (const [key, value] of Object.entries(out)) { + if (typeof value === "string") out[key] = normalizeLineEndings(value) + } + return out as T +} + /** * Append a row to the transcript, folding a groupable tool call into the tool * group directly before it (or starting a new one). Any other row — assistant