Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/fix-windows-task-output-frames.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@moonshot-ai/kimi-code": patch
---

Fix task browser frames becoming misaligned when Windows background task output contains terminal control characters.
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import type { BackgroundTaskInfo, BackgroundTaskStatus } from '@moonshot-ai/kimi

import { currentTheme } from '#/tui/theme';
import { printableChar } from '@/tui/utils/printable-key';
import { sanitizeShellOutput } from '@/tui/utils/shell-output';

const ELLIPSIS = '…';

Expand Down Expand Up @@ -104,7 +105,7 @@ export class TaskOutputViewer extends Container implements Focusable {
}

private splitOutput(output: string): string[] {
return (output.length > 0 ? output : '[no output captured]').split('\n');
return sanitizeShellOutput(output.length > 0 ? output : '[no output captured]').split('\n');
}

// ── input ──────────────────────────────────────────────────────────
Expand Down
3 changes: 2 additions & 1 deletion apps/kimi-code/src/tui/components/dialogs/tasks-browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import type { BackgroundTaskInfo, BackgroundTaskStatus } from '@moonshot-ai/kimi
import { SELECT_POINTER } from '@/tui/constant/symbols';
import { currentTheme } from '#/tui/theme';
import { printableChar } from '@/tui/utils/printable-key';
import { sanitizeShellOutput } from '@/tui/utils/shell-output';

const ELLIPSIS = '…';

Expand Down Expand Up @@ -605,7 +606,7 @@ export class TasksBrowserApp extends Container implements Focusable {
body = '[no output captured]';
else body = this.props.tailOutput;

const rawLines = body.split('\n');
const rawLines = sanitizeShellOutput(body).split('\n');
const tailLines = rawLines.slice(-innerHeight);
const styled = tailLines.map((line) => currentTheme.fg('textDim', line));
while (styled.length < innerHeight) styled.push('');
Expand Down
8 changes: 8 additions & 0 deletions apps/kimi-code/test/tui/task-output-viewer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ describe('TaskOutputViewer — rendering', () => {
expect(lines.length).toBe(24);
});

it('removes carriage returns from Windows task output so frames stay aligned', () => {
const lines = makeViewer({
output: 'Reply from 127.0.0.1: time<1ms TTL=128\r\nReply from 127.0.0.1: time<1ms TTL=128\r\n',
}).render(120);

expect(lines.every((line) => !line.includes('\r'))).toBe(true);
});

it('shows the task header (id + status + description)', () => {
const out = strip(
makeViewer({
Expand Down
10 changes: 10 additions & 0 deletions apps/kimi-code/test/tui/tasks-browser.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,16 @@ describe('TasksBrowserApp — full-screen rendering', () => {
expect(out).toContain('listening on :3000');
});

it('removes carriage returns from Windows task output so frames stay aligned', () => {
const lines = makeApp({
tasks: [task({ taskId: 'bash-aaaaaaaa' })],
selectedTaskId: 'bash-aaaaaaaa',
tailOutput: 'Reply from 127.0.0.1: time<1ms TTL=128\r\nReply from 127.0.0.1: time<1ms TTL=128\r\n',
}).render(120);

expect(lines.every((line) => !line.includes('\r'))).toBe(true);
});

it('shows a loading state when tail is loading', () => {
const out = strip(
makeApp({
Expand Down