From 6634ee76262f2f7e9d19d1459a95bc03fdc774cf Mon Sep 17 00:00:00 2001 From: sudacode Date: Fri, 20 Feb 2026 03:07:13 -0800 Subject: [PATCH] refactor: extract overlay bootstrap runtime wiring --- docs/subagents/INDEX.md | 2 +- .../codex-task85-20260219T233711Z-46hc.md | 4 + src/main.ts | 87 +++++++++---------- ...overlay-runtime-bootstrap-handlers.test.ts | 66 ++++++++++++++ .../overlay-runtime-bootstrap-handlers.ts | 30 +++++++ 5 files changed, 141 insertions(+), 48 deletions(-) create mode 100644 src/main/runtime/overlay-runtime-bootstrap-handlers.test.ts create mode 100644 src/main/runtime/overlay-runtime-bootstrap-handlers.ts diff --git a/docs/subagents/INDEX.md b/docs/subagents/INDEX.md index 3e3eaf2..00b2350 100644 --- a/docs/subagents/INDEX.md +++ b/docs/subagents/INDEX.md @@ -6,7 +6,7 @@ Read first. Keep concise. | ------------ | -------------- | ---------------------------------------------------- | --------- | ------------------------------------- | ---------------------- | | `codex-generate-minecard-image-20260220T112900Z-vsxr` | `codex-generate-minecard-image` | `Generate media fallbacks (GIF) from assets/minecard.webm and wire README/docs fallback markup` | `done` | `docs/subagents/agents/codex-generate-minecard-image-20260220T112900Z-vsxr.md` | `2026-02-20T11:35:30Z` | | `codex-main` | `planner-exec` | `Fix frequency/N+1 regression in plugin --start flow` | `in_progress` | `docs/subagents/agents/codex-main.md` | `2026-02-19T19:36:46Z` | -| `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T10:17:29Z` | +| `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T11:06:51Z` | | `codex-config-validation-20260219T172015Z-iiyf` | `codex-config-validation` | `Find root cause of config validation error for ~/.config/SubMiner/config.jsonc` | `completed` | `docs/subagents/agents/codex-config-validation-20260219T172015Z-iiyf.md` | `2026-02-19T17:26:17Z` | | `codex-task85-20260219T233711Z-46hc` | `codex-task85` | `Resume TASK-85 maintainability refactor from latest handoff point` | `in_progress` | `docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md` | `2026-02-20T02:56:34Z` | | `codex-anilist-deeplink-20260219T233926Z` | `anilist-deeplink` | `Fix external subminer:// AniList callback handling from browser` | `done` | `docs/subagents/agents/codex-anilist-deeplink-20260219T233926Z.md` | `2026-02-19T23:59:21Z` | diff --git a/docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md b/docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md index 582498f..c962123 100644 --- a/docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md +++ b/docs/subagents/agents/codex-task85-20260219T233711Z-46hc.md @@ -9,6 +9,10 @@ ## Current Work (newest first) +- [2026-02-20T11:06:51Z] progress: extracted overlay bootstrap composition from `src/main.ts` into `src/main/runtime/overlay-runtime-bootstrap-handlers.ts`; `main.ts` now creates `initializeOverlayRuntime` through `createOverlayRuntimeBootstrapHandlers(...)`. +- [2026-02-20T11:06:51Z] progress: added `src/main/runtime/overlay-runtime-bootstrap-handlers.test.ts` for composed bootstrap behavior. +- [2026-02-20T11:06:51Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + focused suites pass for `overlay-runtime-bootstrap-handlers*`, `overlay-runtime-bootstrap*`, `overlay-runtime-options*`, `overlay-window-runtime-handlers*`, `tray-runtime-handlers*`, and `cli-command-context-factory*` (8/8). +- [2026-02-20T11:06:51Z] scope: staging `src/main.ts`, new overlay bootstrap handlers module/tests, and subagent bookkeeping only. - [2026-02-20T10:17:29Z] progress: extracted Yomitan settings opener composition from `src/main.ts` into `src/main/runtime/yomitan-settings-runtime.ts`; `main.ts` now uses `createYomitanSettingsRuntime(...)` and consumes `openYomitanSettings` from that runtime. - [2026-02-20T10:17:29Z] progress: added `src/main/runtime/yomitan-settings-runtime.test.ts` for composed runtime behavior. - [2026-02-20T10:17:29Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + focused suites pass for `yomitan-settings-runtime*`, `yomitan-settings-opener*`, `yomitan-extension-runtime*`, `cli-command-context-factory*`, and `tray-runtime-handlers*` (7/7). diff --git a/src/main.ts b/src/main.ts index 41ba599..86e0dc4 100644 --- a/src/main.ts +++ b/src/main.ts @@ -289,7 +289,6 @@ import { createBuildUpdateVisibleOverlayBoundsMainDepsHandler, } from './main/runtime/overlay-window-layout-main-deps'; import { buildTrayMenuTemplateRuntime, resolveTrayIconPathRuntime } from './main/runtime/tray-runtime'; -import { createInitializeOverlayRuntimeHandler } from './main/runtime/overlay-runtime-bootstrap'; import { createGetConfiguredShortcutsHandler, createRefreshGlobalAndOverlayShortcutsHandler, @@ -381,14 +380,10 @@ import { import { createIpcRuntimeHandlers } from './main/runtime/ipc-runtime-handlers'; import { createBuildMpvCommandFromIpcRuntimeMainDepsHandler } from './main/runtime/ipc-mpv-command-main-deps'; import { createOverlayWindowRuntimeHandlers } from './main/runtime/overlay-window-runtime-handlers'; -import { - createBuildInitializeOverlayRuntimeBootstrapMainDepsHandler, -} from './main/runtime/app-runtime-main-deps'; +import { createOverlayRuntimeBootstrapHandlers } from './main/runtime/overlay-runtime-bootstrap-handlers'; import { createTrayRuntimeHandlers } from './main/runtime/tray-runtime-handlers'; import { createYomitanExtensionRuntime } from './main/runtime/yomitan-extension-runtime'; import { createYomitanSettingsRuntime } from './main/runtime/yomitan-settings-runtime'; -import { createBuildInitializeOverlayRuntimeOptionsHandler } from './main/runtime/overlay-runtime-options'; -import { createBuildInitializeOverlayRuntimeMainDepsHandler } from './main/runtime/overlay-runtime-options-main-deps'; import { createOnWillQuitCleanupHandler, createRestoreWindowsOnActivateHandler, @@ -3082,49 +3077,47 @@ const yomitanExtensionRuntime = createYomitanExtensionRuntime({ yomitanLoadInFlight = promise; }, }); -const buildInitializeOverlayRuntimeOptionsHandler = createBuildInitializeOverlayRuntimeOptionsHandler( - createBuildInitializeOverlayRuntimeMainDepsHandler({ - appState, - overlayManager: { - getVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(), - getInvisibleOverlayVisible: () => overlayManager.getInvisibleOverlayVisible(), +const { initializeOverlayRuntime: initializeOverlayRuntimeHandler } = + createOverlayRuntimeBootstrapHandlers({ + initializeOverlayRuntimeMainDeps: { + appState, + overlayManager: { + getVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(), + getInvisibleOverlayVisible: () => overlayManager.getInvisibleOverlayVisible(), + }, + overlayVisibilityRuntime: { + updateVisibleOverlayVisibility: () => overlayVisibilityRuntime.updateVisibleOverlayVisibility(), + updateInvisibleOverlayVisibility: () => + overlayVisibilityRuntime.updateInvisibleOverlayVisibility(), + }, + overlayShortcutsRuntime: { + syncOverlayShortcuts: () => overlayShortcutsRuntime.syncOverlayShortcuts(), + }, + getInitialInvisibleOverlayVisibility: () => + configDerivedRuntime.getInitialInvisibleOverlayVisibility(), + createMainWindow: () => createMainWindow(), + createInvisibleWindow: () => createInvisibleWindow(), + registerGlobalShortcuts: () => registerGlobalShortcuts(), + updateVisibleOverlayBounds: (geometry) => updateVisibleOverlayBounds(geometry), + updateInvisibleOverlayBounds: (geometry) => updateInvisibleOverlayBounds(geometry), + getOverlayWindows: () => getOverlayWindows(), + getResolvedConfig: () => getResolvedConfig(), + showDesktopNotification, + createFieldGroupingCallback: () => createFieldGroupingCallback() as never, + getKnownWordCacheStatePath: () => path.join(USER_DATA_PATH, 'known-words-cache.json'), }, - overlayVisibilityRuntime: { - updateVisibleOverlayVisibility: () => overlayVisibilityRuntime.updateVisibleOverlayVisibility(), - updateInvisibleOverlayVisibility: () => - overlayVisibilityRuntime.updateInvisibleOverlayVisibility(), + initializeOverlayRuntimeBootstrapDeps: { + isOverlayRuntimeInitialized: () => appState.overlayRuntimeInitialized, + initializeOverlayRuntimeCore: (options) => initializeOverlayRuntimeCore(options as never), + setInvisibleOverlayVisible: (visible) => { + overlayManager.setInvisibleOverlayVisible(visible); + }, + setOverlayRuntimeInitialized: (initialized) => { + appState.overlayRuntimeInitialized = initialized; + }, + startBackgroundWarmups: () => startBackgroundWarmups(), }, - overlayShortcutsRuntime: { - syncOverlayShortcuts: () => overlayShortcutsRuntime.syncOverlayShortcuts(), - }, - getInitialInvisibleOverlayVisibility: () => - configDerivedRuntime.getInitialInvisibleOverlayVisibility(), - createMainWindow: () => createMainWindow(), - createInvisibleWindow: () => createInvisibleWindow(), - registerGlobalShortcuts: () => registerGlobalShortcuts(), - updateVisibleOverlayBounds: (geometry) => updateVisibleOverlayBounds(geometry), - updateInvisibleOverlayBounds: (geometry) => updateInvisibleOverlayBounds(geometry), - getOverlayWindows: () => getOverlayWindows(), - getResolvedConfig: () => getResolvedConfig(), - showDesktopNotification, - createFieldGroupingCallback: () => createFieldGroupingCallback() as never, - getKnownWordCacheStatePath: () => path.join(USER_DATA_PATH, 'known-words-cache.json'), - })(), -); -const initializeOverlayRuntimeHandler = createInitializeOverlayRuntimeHandler( - createBuildInitializeOverlayRuntimeBootstrapMainDepsHandler({ - isOverlayRuntimeInitialized: () => appState.overlayRuntimeInitialized, - initializeOverlayRuntimeCore: (options) => initializeOverlayRuntimeCore(options as never), - buildOptions: () => buildInitializeOverlayRuntimeOptionsHandler(), - setInvisibleOverlayVisible: (visible) => { - overlayManager.setInvisibleOverlayVisible(visible); - }, - setOverlayRuntimeInitialized: (initialized) => { - appState.overlayRuntimeInitialized = initialized; - }, - startBackgroundWarmups: () => startBackgroundWarmups(), - })(), -); + }); const { openYomitanSettings: openYomitanSettingsHandler } = createYomitanSettingsRuntime({ ensureYomitanExtensionLoaded: () => ensureYomitanExtensionLoaded(), openYomitanSettingsWindow: ({ yomitanExt, getExistingWindow, setWindow }) => { diff --git a/src/main/runtime/overlay-runtime-bootstrap-handlers.test.ts b/src/main/runtime/overlay-runtime-bootstrap-handlers.test.ts new file mode 100644 index 0000000..d051e92 --- /dev/null +++ b/src/main/runtime/overlay-runtime-bootstrap-handlers.test.ts @@ -0,0 +1,66 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { createOverlayRuntimeBootstrapHandlers } from './overlay-runtime-bootstrap-handlers'; + +test('overlay runtime bootstrap handlers compose options builder and bootstrap handler', () => { + const appState = { + backendOverride: null as string | null, + windowTracker: null as unknown, + subtitleTimingTracker: null as unknown, + mpvClient: null as unknown, + mpvSocketPath: '/tmp/mpv.sock', + runtimeOptionsManager: null as unknown, + ankiIntegration: null as unknown, + }; + let initialized = false; + let invisibleOverlayVisible = false; + let warmupsStarted = 0; + + const { initializeOverlayRuntime } = createOverlayRuntimeBootstrapHandlers({ + initializeOverlayRuntimeMainDeps: { + appState, + overlayManager: { + getVisibleOverlayVisible: () => true, + getInvisibleOverlayVisible: () => false, + }, + overlayVisibilityRuntime: { + updateVisibleOverlayVisibility: () => {}, + updateInvisibleOverlayVisibility: () => {}, + }, + overlayShortcutsRuntime: { + syncOverlayShortcuts: () => {}, + }, + getInitialInvisibleOverlayVisibility: () => false, + createMainWindow: () => {}, + createInvisibleWindow: () => {}, + registerGlobalShortcuts: () => {}, + updateVisibleOverlayBounds: () => {}, + updateInvisibleOverlayBounds: () => {}, + getOverlayWindows: () => [], + getResolvedConfig: () => ({}), + showDesktopNotification: () => {}, + createFieldGroupingCallback: () => (async () => 'combined' as never), + getKnownWordCacheStatePath: () => '/tmp/known.json', + }, + initializeOverlayRuntimeBootstrapDeps: { + isOverlayRuntimeInitialized: () => initialized, + initializeOverlayRuntimeCore: () => ({ invisibleOverlayVisible: true }), + setInvisibleOverlayVisible: (visible) => { + invisibleOverlayVisible = visible; + }, + setOverlayRuntimeInitialized: (next) => { + initialized = next; + }, + startBackgroundWarmups: () => { + warmupsStarted += 1; + }, + }, + }); + + initializeOverlayRuntime(); + initializeOverlayRuntime(); + + assert.equal(invisibleOverlayVisible, true); + assert.equal(initialized, true); + assert.equal(warmupsStarted, 1); +}); diff --git a/src/main/runtime/overlay-runtime-bootstrap-handlers.ts b/src/main/runtime/overlay-runtime-bootstrap-handlers.ts new file mode 100644 index 0000000..0e5d220 --- /dev/null +++ b/src/main/runtime/overlay-runtime-bootstrap-handlers.ts @@ -0,0 +1,30 @@ +import { createBuildInitializeOverlayRuntimeBootstrapMainDepsHandler } from './app-runtime-main-deps'; +import { createInitializeOverlayRuntimeHandler } from './overlay-runtime-bootstrap'; +import { createBuildInitializeOverlayRuntimeOptionsHandler } from './overlay-runtime-options'; +import { createBuildInitializeOverlayRuntimeMainDepsHandler } from './overlay-runtime-options-main-deps'; + +type InitializeOverlayRuntimeMainDeps = Parameters< + typeof createBuildInitializeOverlayRuntimeMainDepsHandler +>[0]; +type InitializeOverlayRuntimeBootstrapMainDeps = Parameters< + typeof createBuildInitializeOverlayRuntimeBootstrapMainDepsHandler +>[0]; + +export function createOverlayRuntimeBootstrapHandlers(deps: { + initializeOverlayRuntimeMainDeps: InitializeOverlayRuntimeMainDeps; + initializeOverlayRuntimeBootstrapDeps: Omit; +}) { + const buildInitializeOverlayRuntimeOptionsHandler = createBuildInitializeOverlayRuntimeOptionsHandler( + createBuildInitializeOverlayRuntimeMainDepsHandler(deps.initializeOverlayRuntimeMainDeps)(), + ); + const initializeOverlayRuntime = createInitializeOverlayRuntimeHandler( + createBuildInitializeOverlayRuntimeBootstrapMainDepsHandler({ + ...deps.initializeOverlayRuntimeBootstrapDeps, + buildOptions: () => buildInitializeOverlayRuntimeOptionsHandler(), + })(), + ); + + return { + initializeOverlayRuntime, + }; +}