galaxyproject / galaxyproject/loom

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

Open
#36 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
TypeScript
Stars
14
Forks
12
Avg merge
6d 5h
Merged PRs (30d)
17

Description

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.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reading app.ts, markdown.ts, and index.html, then review commits 43db513 and 2b6a571 for the renderer initialization context. The issue contains three related but independent concerns: renderer failure visibility, app.ts extraction, and the initial status badge. Done should be defined separately for each small change while keeping the app working.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
frontend
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.