- PERF8: code-split the non-default tabs. Library/History/Terminal/Settings are
React.lazy chunks behind a Suspense; Downloads (the launch tab) stays eager. The
production build now emits separate SettingsView (~90kB), LibraryView (~29kB),
HistoryView (~16kB), TerminalView (~8kB) chunks — ~140kB out of the initial
bundle. The stores these views use are imported eagerly elsewhere, so lazy-
loading the views never delays store startup/persistence (per the C2 note).
- L128: gate the three preview seed arrays (downloadSeed / sources seeds / history
seed) on `import.meta.env.DEV && PREVIEW`. In the packaged build DEV is
statically false, so Rollup constant-folds and dead-code-eliminates the seed
literals; the browser dev preview (DEV true) still gets them.
- SR4: clipboardWatch now defaults false for new installs (privacy — no clipboard
read on focus until opted in). Existing installs keep their saved value
(electron-store fills only missing keys); the onboarding tip points to the
setting. NOTE: this flips a signature convenience off-by-default for new users —
flagged for the maintainer, trivially reversible.
Deferred with rationale (CODE-AUDIT.md): PERF3 (core-queue micro-opt on a bounded
list, risky unattended), PERF6/L162 (bounded by virtualization + conflicts with
PERF5's hoisted renderItem), SR5 (MP3 = deliberate compatibility default; the label
bug was M18), W12 (fallback-of-a-fallback icon), W15 (GPU software-rendering
workaround — external driver dependency), L104 (History virtualization needs the
L161 layout rework + live verification; bounded by the 500-cap).
Verified: typecheck (node+web) + 279 tests + eslint + production build green
(code-split chunks confirmed in output); touched files prettier-clean.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
live-verify). All green: typecheck (node+web) + 279 tests + eslint + production build; touched files
live-verify). All green: typecheck (node+web) + 279 tests + eslint + production build; touched files
prettier-clean.
prettier-clean.
**Session 2026-07-01 pass 11 (Batch 14 — perf + first-run defaults + Windows):** two real bundle/startup wins
plus one first-run default. **PERF8** — Library/History/Terminal/Settings are `React.lazy` chunks behind a
`Suspense` (Downloads stays eager); the production build now splits ~140 kB (incl. the 90 kB SettingsView) out
of the initial bundle. **L128** — the three preview seed arrays are gated on `import.meta.env.DEV && PREVIEW`,
so Rollup dead-code-eliminates them from the packaged renderer (DEV statically false) while the browser dev
preview keeps them. **SR4** — `clipboardWatch` now defaults `false` for new installs (privacy-first; existing
installs keep their saved value; Onboarding tip repointed) — *a product default flip flagged for the
maintainer, trivially reversible.* **Deferred with rationale:****PERF3** (core-queue micro-opt on a bounded
list — risk > reward unattended, revisit in the Batch 15 live pass), **PERF6/L162** (bounded by
virtualization; a prop conflicts with PERF5's hoisted renderItem), **SR5** (MP3 = deliberate
max-compatibility default; the label bug was M18), **W12** (fallback-of-a-fallback icon), **W15** (the GPU
software-rendering workaround — external driver dependency), and **L104** (History virtualization needs the
L161 layout rework + live verification; the 500-cap bounds it). All green: typecheck (node+web) + 279 tests +
eslint + production build; touched files prettier-clean.
**Deliberately deferred** (need live-app/visual verification or are larger refactors the
**Deliberately deferred** (need live-app/visual verification or are larger refactors the
audit itself defers to 1.x): the wire-or-cut features (M5/M6/UX1), the god-file/store
audit itself defers to 1.x): the wire-or-cut features (M5/M6/UX1), the god-file/store
refactors (C1, C2, H1), the SIMP* helpers + shared-UI-token work, the CC* consolidations,
refactors (C1, C2, H1), the SIMP* helpers + shared-UI-token work, the CC* consolidations,
@@ -916,9 +931,12 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
remaining `<Spinner>`s are standalone status-row indicators (the "Fetching…"/"Waiting to start…"/indexing
remaining `<Spinner>`s are standalone status-row indicators (the "Fetching…"/"Waiting to start…"/indexing
rows), not a button + adjacent spinner. No separate-adjacent-spinner pattern survives.*
rows), not a button + adjacent spinner. No separate-adjacent-spinner pattern survives.*
- [ ]**L104 — History isn't virtualized.** It renders all filtered rows, while Downloads and Library use `VirtualList`.
- [ ]**L104 — History isn't virtualized.** It renders all filtered rows, while Downloads and Library use `VirtualList`.
*Moved to Batch 14 (perf): virtualizing History is a rendering-performance change (it belongs with the other
*Deferred (bounded; needs the L161 layout rework + live verification): History is capped at 500 rows (L141),
perf items — PERF3/L162), not copy/cleanup. Capped at 500 entries (L141), so the current cost is bounded but
so the un-virtualized render is bounded — not a real perf problem. Virtualizing it requires giving the list a
worth virtualizing for consistency; done in the perf batch.*
fixed-height internal scroll container (the same `height:100%`/`overflow` rework L161 flags as needing
live verification at multiple window sizes) *and* re-homing its container-level Ctrl+A and per-row Delete
keyboard handling onto the virtualized scroller. That's a layout+interaction change best done watched, so it
rides with L161 rather than shipping unattended for a list that's already capped.*
- [x]**L105 — `MediaKind` declared twice.** In both [ipc.ts](src/shared/ipc.ts) and
- [x]**L105 — `MediaKind` declared twice.** In both [ipc.ts](src/shared/ipc.ts) and
[store/downloads.ts](src/renderer/src/store/downloads.ts); components import it from both. Single source it.
[store/downloads.ts](src/renderer/src/store/downloads.ts); components import it from both. Single source it.
*Fixed: the store now imports `MediaKind` from `@shared/ipc` and re-exports it, so the duplicate local
*Fixed: the store now imports `MediaKind` from `@shared/ipc` and re-exports it, so the duplicate local
@@ -1018,11 +1036,14 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
(the header is now `title`), and the shared `Banner` content (UI19). `title` also gained `minWidth:0` so it
(the header is now `title`), and the shared `Banner` content (UI19). `title` also gained `minWidth:0` so it
shrinks correctly in a flex row. (Remaining correct-but-inline truncations migrate to the util incrementally.)*
shrinks correctly in a flex row. (Remaining correct-but-inline truncations migrate to the util incrementally.)*
- [x] **L127 — `Notification` sets no icon** — completion toasts used the default Electron icon though `getAppIconPath()` existed. *Fixed with W13 (cached `getAppIconImage()` passed as `icon` at both notification sites).*
- [x] **L127 — `Notification` sets no icon** — completion toasts used the default Electron icon though `getAppIconPath()` existed. *Fixed with W13 (cached `getAppIconImage()` passed as `icon` at both notification sites).*
- [] **L128 — Preview seed/mock data ships in production.** The `PREVIEW` runtime check can't be
- [x] **L128 — Preview seed/mock data ships in production.** The `PREVIEW` runtime check can't be
tree-shaken, so each store's seed arrays + fake ticker are bundled into the Electron renderer.
tree-shaken, so each store's seed arrays + fake ticker are bundled into the Electron renderer.
*Deferred to Batch 14 (perf/bundle): this is a build-time dead-code-elimination concern (gate the seed
*Fixed: the three preview seed arrays (`downloadSeed`, `sources` `seedSources`/`seedItemsBySource`,
imports behind `import.meta.env` so Rollup drops them from the packaged renderer), grouped with PERF8's
`history` seed) are now gated on `import.meta.env.DEV && PREVIEW`. In the packaged renderer build
code-splitting where the lazy-loading is set up. Left open on purpose.*
`import.meta.env.DEV` is statically `false`, so Rollup constant-folds `false && …` and dead-code-eliminates
the whole seed literal; the browser dev preview (`vite`, DEV `true`) still gets them. (The small `PREVIEW`
fake-ticker function stays — it's tied to the runtime flag and is a few lines; the bulky part was the data,
now dropped.)*
- [x] **L129 — `Hint align` is silently ignored for left/right placements** yet callers still pass it.
- [x] **L129 — `Hint align` is silently ignored for left/right placements** yet callers still pass it.
*Fixed: `HintProps` is now a discriminated union — `align` is only accepted with `placement` `top`/`bottom`;
*Fixed: `HintProps` is now a discriminated union — `align` is only accepted with `placement` `top`/`bottom`;
passing it with `left`/`right` is a compile error instead of a silent no-op. No caller needed changing (the
passing it with `left`/`right` is a compile error instead of a silent no-op. No caller needed changing (the
@@ -1189,7 +1210,9 @@ token system + shared primitives (UI/SIMP — high value, larger effort) · i18n
a layout change best validated with the app open at several window sizes — a watched pass, not an unattended
a layout change best validated with the app open at several window sizes — a watched pass, not an unattended
edit.*
edit.*
- [ ] **L162 — Per-thumbnail store subscription.** Every `MediaThumb` calls `useResolvedDark()` (two store
- [ ] **L162 — Per-thumbnail store subscription.** Every `MediaThumb` calls `useResolvedDark()` (two store
subscriptions) instead of receiving a resolved theme prop — N subscriptions per list.
subscriptions) instead of receiving a resolved theme prop — N subscriptions per list. *Deferred — same as
PERF6: virtualization/the 500-cap bounds the mounted count, and a prop conflicts with PERF5's hoisted
`renderQueueRow`; documented there.*
- [x] **L163 — QueueItem makes 9 separate `useDownloads` selector calls** instead of one destructured
- [x] **L163 — QueueItem makes 9 separate `useDownloads` selector calls** instead of one destructured
selection — repeated boilerplate per row. *Fixed: one `useShallow` selection replaces the 10 individual
selection — repeated boilerplate per row. *Fixed: one `useShallow` selection replaces the 10 individual
subscriptions in [QueueItem.tsx](src/renderer/src/components/QueueItem.tsx) (the actions are stable, so the
subscriptions in [QueueItem.tsx](src/renderer/src/components/QueueItem.tsx) (the actions are stable, so the
@@ -1708,6 +1731,10 @@ DPI handled by Chromium). The deviations:
- [ ] **W12 — Fallback tray icon is single-resolution.** The embedded fallback is a 32×32 PNG, so on
- [ ] **W12 — Fallback tray icon is single-resolution.** The embedded fallback is a 32×32 PNG, so on
150%/200% DPI the tray glyph is blurry when the real multi-size `.ico` is absent. **Standard:** a
150%/200% DPI the tray glyph is blurry when the real multi-size `.ico` is absent. **Standard:** a
multi-size fallback (or rely only on the `.ico`).
multi-size fallback (or rely only on the `.ico`).
*Deferred (low value, needs the real tray to judge): the fallback only renders in the unlikely case the
bundled multi-size `build/icon.ico` is missing (W14 regenerated it), so it's a fallback-of-a-fallback. A
multi-res embedded base64 is fiddly to author and best verified on a real high-DPI tray — not worth an
unattended change for a path that shouldn't be hit.*
- [x] **W13 — Notifications set no icon.** `new Notification({title, body})` omitted `icon`; on the **portable**
- [x] **W13 — Notifications set no icon.** `new Notification({title, body})` omitted `icon`; on the **portable**
build (no installed AUMID shortcut) Windows toasts showed a generic icon. *Fixed: both notification sites
build (no installed AUMID shortcut) Windows toasts showed a generic icon. *Fixed: both notification sites
// greeted by a bright white window despite full system-theme support.
// greeted by a bright white window despite full system-theme support.
theme:'system',
theme:'system',
accentColor:'teal',
accentColor:'teal',
clipboardWatch: true,
// Off on first launch (SR4): reading the clipboard on every window focus is a
// privacy surprise for a brand-new user. It's a one-toggle opt-in in Settings
// (the onboarding tip points there). Existing installs keep their saved value.
clipboardWatch: false,
downloadOptions: DEFAULT_DOWNLOAD_OPTIONS,
downloadOptions: DEFAULT_DOWNLOAD_OPTIONS,
proxy:'',
proxy:'',
rateLimit:'',
rateLimit:'',
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.