Files
claude code agent 8ca0608b21 fix(logs): stable line ids, JSON string guard, streaming demuxer helper
Foundation for append-only log rendering and HTTP log streaming.

- FormattedLine gains a stable, monotonically increasing `id` (new
  lineId.ts sequence), assigned centrally in formatLogs. Internal
  formatters now return id-less FormattedLineContent. This lets the
  viewer use `track by log.id` so already-rendered rows are never
  re-bound (fixes the text-selection collapse).
- formatJSONLine: runtime guard so a bare JSON string/array log line
  falls back to plain text instead of rendering Object.keys as
  `0=h 1=e ...`.
- createLogStreamProcessor: stateful demuxer that buffers streamed text,
  emits only complete lines (carrying the partial remainder), and reuses
  formatLogs/stripHeadersFunc for Docker 8-byte frame demux.
- Unit tests for the demuxer, stable-id assignment and the JSON guard.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-29 07:03:10 +03:00

27 lines
962 B
TypeScript

import { formatJSONLine } from './formatJSONLogs';
describe('formatJSONLine 0=d 1=e guard', () => {
it('renders a bare JSON string as plain text (not index=char pairs)', () => {
const raw = '"hello"';
const lines = formatJSONLine(raw);
expect(lines).toHaveLength(1);
// faithfully passes the raw line through instead of iterating its chars
expect(lines[0].line).toBe(raw);
// would previously have produced "0=h 1=e 2=l ..." via Object.keys on a string
expect(lines[0].line).not.toContain('0=h');
});
it('renders a bare JSON array as plain text', () => {
const raw = '[1,2,3]';
const lines = formatJSONLine(raw);
expect(lines).toHaveLength(1);
expect(lines[0].line).toBe(raw);
});
it('still parses a real JSON-object log line', () => {
const lines = formatJSONLine('{"level":"info","message":"hi"}');
expect(lines[0].line).toContain('hi');
expect(lines[0].line).not.toContain('0=');
});
});