Skip to content

Orbit: renderer init brittleness — silent module-throw kills app, app.ts monolith, badge HTML lies #36

@nekrut

Description

@nekrut

Surfaced while debugging a stuck "connecting…" footer badge after the
DOMPurify hardening (C1). Three related concerns; each independent.

1. Renderer init has no error surface

A throw in any module reachable from app.ts aborts the whole renderer.
The user sees a frozen UI and no error indication. Today's example:
markdown.ts did import * as DOMPurifyMod from "dompurify" and called
DOMPurifyMod.addHook(...) — the namespace had no such method, threw
at module top level, killed everything downstream (status badge, IPC
listeners, shortcuts).

Suggestions:

  • Global window.onerror + window.onunhandledrejection that paint a
    visible banner (footer or toast) with the error + reload affordance.
  • Move side-effectful top-level code in app.ts into an explicit
    bootstrap() function so init failure is catchable in one place.

2. app.ts is ~2500 lines

Contributing factor to #1 (one module to break, one module to grep).
Suggested split (rough — can be revisited):

  • `chat-controller.ts` — message send/abort/streaming wiring
  • `status.ts` — agent + galaxy status badges
  • `prefs.ts` — Preferences modal + Galaxy/API key flows
  • `files-panel.ts` — left-pane file tree (already partially extracted)
  • `bootstrap.ts` — DOM-ready glue, error handler, listener attach order

Not a single PR. Stack of small, mechanical extractions; each PR keeps
the app working.

3. Hardcoded "connecting…" in index.html

`connecting...` is what the user sees if
anything in the init chain breaks before the first `setStatusBadge`
call. This is what made #1 so visible — a stuck UI that lied about the
brain state.

Suggestions:

  • Start the badge empty (or `"…"`) so an unset state looks unset.
  • Push brain init progress through the badge or chat (spawn → MCP boot
    → ready) so a slow startup doesn't look frozen.
  • Consider merging the `agent-status` pill and the `galaxy-status` dot
    into one "system status" widget — they represent related states and
    two unrelated controls makes the footer noisier than it needs to be.

Recent context

  • Race fix landed in 43db513: `agent:get-status` snapshot pulled by
    renderer after listener attach. Defends against listener-attached-
    after-event ordering, but doesn't help when the renderer fails to
    load at all (today's case — DOMPurify import).
  • DOMPurify import fix landed in 2b6a571.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions