Files
openchamber/packages/ui/src/sync/session-error-log.test.ts
T
Bohdan Triapitsyn b18933f19c feat(chat): surface failed turns and add error diagnostics to the status report
A turn that OpenCode stopped could end with nothing on screen: the
session.error event was only turned into a sidebar badge, its message was
dropped (the notification expected a different shape than OpenCode sends),
and a send that was accepted but never answered looked the same as success.

- The chat shows what OpenCode reported under the last message while that
  turn is the latest one, and names a user message an idle session has left
  unanswered for five seconds.
- The last 20 session errors are kept in memory and listed in the status
  report (Ctrl/Cmd+Shift+L, also `__opencodeDebug.statusReport()`), next to
  rejected sends, the managed OpenCode process's last error and stderr
  tail, and the OpenCode and desktop log file locations.
- The OpenCode health probe hits /global/health instead of a route that
  does not exist, and probe URLs resolve against the page for web runtimes.
2026-08-29 23:22:27 +03:00

33 lines
1.6 KiB
TypeScript

import { describe, expect, test } from 'bun:test';
import { getRecentSessionErrors, recordSessionError, summarizeOpenCodeError } from './session-error-log';
describe('summarizeOpenCodeError', () => {
test('reads the OpenCode shape: name plus data.message', () => {
expect(summarizeOpenCodeError({ name: 'ProviderAuthError', data: { providerID: 'openai', message: 'Invalid API key' } }))
.toEqual({ name: 'ProviderAuthError', message: 'Invalid API key' });
});
test('falls back to a top-level message and reports missing details as null', () => {
expect(summarizeOpenCodeError({ message: 'socket hang up' })).toEqual({ name: null, message: 'socket hang up' });
expect(summarizeOpenCodeError({ name: 'UnknownError', data: { message: ' ' } })).toEqual({ name: 'UnknownError', message: null });
expect(summarizeOpenCodeError(undefined)).toEqual({ name: null, message: null });
});
test('bounds the message length', () => {
const summary = summarizeOpenCodeError({ name: 'UnknownError', data: { message: 'x'.repeat(1000) } });
expect(summary.message?.length).toBe(400);
});
});
describe('recordSessionError', () => {
test('keeps the newest records first and caps the buffer', () => {
for (let index = 0; index < 25; index += 1) {
recordSessionError({ sessionId: `ses_${index}`, directory: null, name: 'UnknownError', message: `error ${index}` });
}
const records = getRecentSessionErrors();
expect(records.length).toBe(20);
expect(records[0]?.sessionId).toBe('ses_24');
expect(records[19]?.sessionId).toBe('ses_5');
});
});