galaxyproject / galaxyproject/loom
Orbit: renderer init brittleness — silent module-throw kills app, app.ts monolith, badge HTML lies
- 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