codeburn/app/renderer/lib/ipc.ts
iamtoruk 9e6ea306fe feat(app): T8 integration + cleanup — single refresh, ⌘-nav, shared error/format/period/series, README
- One 30s refresh + manual ⌘R; footer shows real last-fetch time; getOverview fetched once (no double-poll).
- Keyboard nav: ⌘1–⌘5/⌘, switch sections, ⌘R refresh.
- Verified period/provider re-polls all sections.
- Shared CliErrorPanel: amber permission ("Full Disk Access") vs red error, used by every section.
- DRY: shared lib/format.ts (USD), lib/period.ts (Overview migrated to it), lib/modelSeries.ts (unified model→series).
- Settings review-minor tests (!paired filter, empty/not-found states) + App.test.tsx.
- app/README.md incl. the approved M2 delivery model (self-contained, bundles engine, Electron auto-updater).
- 76 tests, typecheck clean. Live GUI smoke (npm --prefix app run dev) still pending a display.

Implemented by Codex gpt-5.5 (high); committed by Fable (git blocked in Codex sandbox).
2026-07-10 19:35:41 -07:00

23 lines
888 B
TypeScript

import type { CliError, CodeburnBridge } from './types'
// The preload script (app/electron/preload.ts) exposes `window.codeburn` as the
// typed CodeburnBridge (methods resolve to CLI JSON or reject with a plain
// CliError).
declare global {
interface Window {
codeburn: CodeburnBridge
}
}
/** The typed bridge. Import this instead of touching `window` directly. */
export const codeburn: CodeburnBridge = window.codeburn
/** Coerce anything thrown across the IPC boundary into a CliError shape. */
export function normalizeCliError(err: unknown): CliError {
if (err && typeof err === 'object' && 'kind' in err && typeof (err as CliError).kind === 'string') {
const e = err as CliError
return { kind: e.kind, message: e.message ?? 'codeburn CLI error' }
}
const message = err instanceof Error ? err.message : String(err)
return { kind: 'nonzero', message }
}