From 5b432fa15609c0209ffb01183a2a3658123a3258 Mon Sep 17 00:00:00 2001 From: sudacode Date: Fri, 20 Feb 2026 02:02:52 -0800 Subject: [PATCH] refactor: extract overlay visibility runtime wiring --- docs/subagents/INDEX.md | 2 +- .../codex-task85-20260219T233711Z-46hc.md | 4 + src/main.ts | 116 +++++------------- .../overlay-visibility-runtime.test.ts | 74 +++++++++++ .../runtime/overlay-visibility-runtime.ts | 78 ++++++++++++ 5 files changed, 191 insertions(+), 83 deletions(-) create mode 100644 src/main/runtime/overlay-visibility-runtime.test.ts create mode 100644 src/main/runtime/overlay-visibility-runtime.ts diff --git a/docs/subagents/INDEX.md b/docs/subagents/INDEX.md index 3c2453d..9821135 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-20T09:59:54Z` | +| `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:02:30Z` | | `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 762a272..d8743ea 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-20T10:02:30Z] progress: extracted overlay visibility action composition from `src/main.ts` into new runtime module `src/main/runtime/overlay-visibility-runtime.ts`; `main.ts` now consumes a single `createOverlayVisibilityRuntime(...)` factory for set/toggle overlay handlers. +- [2026-02-20T10:02:30Z] progress: added `src/main/runtime/overlay-visibility-runtime.test.ts` to lock behavior of composed set/toggle/setOverlay/toggleOverlay wiring. +- [2026-02-20T10:02:30Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + focused suites pass for `overlay-visibility-runtime*`, `overlay-visibility-actions*`, `overlay-runtime-bootstrap*`, `overlay-window-layout*`, and `cli-command-context*` (16/16). +- [2026-02-20T10:02:30Z] scope: committing `src/main.ts`, new overlay visibility runtime module/tests, and subagent bookkeeping only. - [2026-02-20T09:59:54Z] progress: pivot batch completed: extracted Yomitan extension runtime wiring from `src/main.ts` into new module `src/main/runtime/yomitan-extension-runtime.ts` and replaced `main.ts` setup with `createYomitanExtensionRuntime(...)`. - [2026-02-20T09:59:54Z] progress: added regression coverage for extracted composition in `src/main/runtime/yomitan-extension-runtime.test.ts`; finalized remaining inline `build*MainDepsHandler(),` constructor sites in `src/main.ts` (count now 0). - [2026-02-20T09:59:54Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + targeted suites pass for `yomitan-extension-runtime*`, `yomitan-extension-loader*`, `mpv-subtitle-render-metrics*`, `overlay-window-layout*`, `mining-actions*`, `ipc-bridge-actions*`, `cli-command-context*`, `startup-warmups*` (30/30). diff --git a/src/main.ts b/src/main.ts index 8bc8d0d..cc157c3 100644 --- a/src/main.ts +++ b/src/main.ts @@ -354,30 +354,15 @@ import { createBuildHandleMineSentenceDigitMainDepsHandler, createBuildHandleMultiCopyDigitMainDepsHandler, } from './main/runtime/mining-actions-main-deps'; -import { - createSetInvisibleOverlayVisibleHandler, - createSetVisibleOverlayVisibleHandler, - createToggleInvisibleOverlayHandler, - createToggleVisibleOverlayHandler, -} from './main/runtime/overlay-visibility-actions'; -import { - createBuildSetInvisibleOverlayVisibleMainDepsHandler, - createBuildSetVisibleOverlayVisibleMainDepsHandler, - createBuildToggleInvisibleOverlayMainDepsHandler, - createBuildToggleVisibleOverlayMainDepsHandler, -} from './main/runtime/overlay-visibility-actions-main-deps'; import { createBuildOverlayVisibilityRuntimeMainDepsHandler } from './main/runtime/overlay-visibility-runtime-main-deps'; +import { createOverlayVisibilityRuntime } from './main/runtime/overlay-visibility-runtime'; import { createAppendClipboardVideoToQueueHandler, createHandleOverlayModalClosedHandler, - createSetOverlayVisibleHandler, - createToggleOverlayHandler, } from './main/runtime/overlay-main-actions'; import { createBuildAppendClipboardVideoToQueueMainDepsHandler, createBuildHandleOverlayModalClosedMainDepsHandler, - createBuildSetOverlayVisibleMainDepsHandler, - createBuildToggleOverlayMainDepsHandler, } from './main/runtime/overlay-main-actions-main-deps'; import { createBroadcastRuntimeOptionsChangedHandler, @@ -2885,77 +2870,44 @@ const handleMineSentenceDigitMainDeps = buildHandleMineSentenceDigitMainDepsHand const handleMineSentenceDigitHandler = createHandleMineSentenceDigitHandler( handleMineSentenceDigitMainDeps, ); -const buildSetVisibleOverlayVisibleMainDepsHandler = - createBuildSetVisibleOverlayVisibleMainDepsHandler({ - setVisibleOverlayVisibleCore, - setVisibleOverlayVisibleState: (nextVisible) => { - overlayManager.setVisibleOverlayVisible(nextVisible); +const { + setVisibleOverlayVisible: setVisibleOverlayVisibleHandler, + setInvisibleOverlayVisible: setInvisibleOverlayVisibleHandler, + toggleVisibleOverlay: toggleVisibleOverlayHandler, + toggleInvisibleOverlay: toggleInvisibleOverlayHandler, + setOverlayVisible: setOverlayVisibleHandler, + toggleOverlay: toggleOverlayHandler, +} = createOverlayVisibilityRuntime({ + setVisibleOverlayVisibleDeps: { + setVisibleOverlayVisibleCore, + setVisibleOverlayVisibleState: (nextVisible) => { + overlayManager.setVisibleOverlayVisible(nextVisible); + }, + updateVisibleOverlayVisibility: () => overlayVisibilityRuntime.updateVisibleOverlayVisibility(), + updateInvisibleOverlayVisibility: () => + overlayVisibilityRuntime.updateInvisibleOverlayVisibility(), + syncInvisibleOverlayMousePassthrough: () => + overlayVisibilityRuntime.syncInvisibleOverlayMousePassthrough(), + shouldBindVisibleOverlayToMpvSubVisibility: () => + configDerivedRuntime.shouldBindVisibleOverlayToMpvSubVisibility(), + isMpvConnected: () => Boolean(appState.mpvClient && appState.mpvClient.connected), + setMpvSubVisibility: (mpvSubVisible) => { + setMpvSubVisibilityRuntime(appState.mpvClient, mpvSubVisible); + }, }, - updateVisibleOverlayVisibility: () => overlayVisibilityRuntime.updateVisibleOverlayVisibility(), - updateInvisibleOverlayVisibility: () => overlayVisibilityRuntime.updateInvisibleOverlayVisibility(), - syncInvisibleOverlayMousePassthrough: () => - overlayVisibilityRuntime.syncInvisibleOverlayMousePassthrough(), - shouldBindVisibleOverlayToMpvSubVisibility: () => - configDerivedRuntime.shouldBindVisibleOverlayToMpvSubVisibility(), - isMpvConnected: () => Boolean(appState.mpvClient && appState.mpvClient.connected), - setMpvSubVisibility: (mpvSubVisible) => { - setMpvSubVisibilityRuntime(appState.mpvClient, mpvSubVisible); + setInvisibleOverlayVisibleDeps: { + setInvisibleOverlayVisibleCore, + setInvisibleOverlayVisibleState: (nextVisible) => { + overlayManager.setInvisibleOverlayVisible(nextVisible); + }, + updateInvisibleOverlayVisibility: () => + overlayVisibilityRuntime.updateInvisibleOverlayVisibility(), + syncInvisibleOverlayMousePassthrough: () => + overlayVisibilityRuntime.syncInvisibleOverlayMousePassthrough(), }, -}); -const setVisibleOverlayVisibleMainDeps = - buildSetVisibleOverlayVisibleMainDepsHandler(); -const setVisibleOverlayVisibleHandler = createSetVisibleOverlayVisibleHandler( - setVisibleOverlayVisibleMainDeps, -); - -const buildSetInvisibleOverlayVisibleMainDepsHandler = - createBuildSetInvisibleOverlayVisibleMainDepsHandler({ - setInvisibleOverlayVisibleCore, - setInvisibleOverlayVisibleState: (nextVisible) => { - overlayManager.setInvisibleOverlayVisible(nextVisible); - }, - updateInvisibleOverlayVisibility: () => overlayVisibilityRuntime.updateInvisibleOverlayVisibility(), - syncInvisibleOverlayMousePassthrough: () => - overlayVisibilityRuntime.syncInvisibleOverlayMousePassthrough(), -}); -const setInvisibleOverlayVisibleMainDeps = - buildSetInvisibleOverlayVisibleMainDepsHandler(); -const setInvisibleOverlayVisibleHandler = createSetInvisibleOverlayVisibleHandler( - setInvisibleOverlayVisibleMainDeps, -); - -const buildToggleVisibleOverlayMainDepsHandler = createBuildToggleVisibleOverlayMainDepsHandler({ getVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(), - setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible), -}); -const toggleVisibleOverlayMainDeps = buildToggleVisibleOverlayMainDepsHandler(); -const toggleVisibleOverlayHandler = createToggleVisibleOverlayHandler( - toggleVisibleOverlayMainDeps, -); - -const buildToggleInvisibleOverlayMainDepsHandler = - createBuildToggleInvisibleOverlayMainDepsHandler({ getInvisibleOverlayVisible: () => overlayManager.getInvisibleOverlayVisible(), - setInvisibleOverlayVisible: (visible) => setInvisibleOverlayVisible(visible), }); -const toggleInvisibleOverlayMainDeps = - buildToggleInvisibleOverlayMainDepsHandler(); -const toggleInvisibleOverlayHandler = createToggleInvisibleOverlayHandler( - toggleInvisibleOverlayMainDeps, -); - -const buildSetOverlayVisibleMainDepsHandler = createBuildSetOverlayVisibleMainDepsHandler({ - setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible), -}); -const setOverlayVisibleMainDeps = buildSetOverlayVisibleMainDepsHandler(); -const setOverlayVisibleHandler = createSetOverlayVisibleHandler( - setOverlayVisibleMainDeps, -); - -const buildToggleOverlayMainDepsHandler = createBuildToggleOverlayMainDepsHandler({ - toggleVisibleOverlay: () => toggleVisibleOverlay(), -}); -const toggleOverlayHandler = createToggleOverlayHandler(buildToggleOverlayMainDepsHandler()); const buildHandleOverlayModalClosedMainDepsHandler = createBuildHandleOverlayModalClosedMainDepsHandler({ diff --git a/src/main/runtime/overlay-visibility-runtime.test.ts b/src/main/runtime/overlay-visibility-runtime.test.ts new file mode 100644 index 0000000..de65798 --- /dev/null +++ b/src/main/runtime/overlay-visibility-runtime.test.ts @@ -0,0 +1,74 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { createOverlayVisibilityRuntime } from './overlay-visibility-runtime'; + +test('overlay visibility runtime wires set/toggle handlers through composed deps', () => { + let visible = false; + let invisible = true; + let setVisibleCoreCalls = 0; + let setInvisibleCoreCalls = 0; + let lastBoundSubVisibility: boolean | null = null; + + const runtime = createOverlayVisibilityRuntime({ + setVisibleOverlayVisibleDeps: { + setVisibleOverlayVisibleCore: (options) => { + setVisibleCoreCalls += 1; + options.setVisibleOverlayVisibleState(options.visible); + options.updateVisibleOverlayVisibility(); + options.updateInvisibleOverlayVisibility(); + options.syncInvisibleOverlayMousePassthrough(); + if (options.shouldBindVisibleOverlayToMpvSubVisibility() && options.isMpvConnected()) { + options.setMpvSubVisibility(options.visible); + } + }, + setVisibleOverlayVisibleState: (nextVisible) => { + visible = nextVisible; + }, + updateVisibleOverlayVisibility: () => {}, + updateInvisibleOverlayVisibility: () => {}, + syncInvisibleOverlayMousePassthrough: () => {}, + shouldBindVisibleOverlayToMpvSubVisibility: () => true, + isMpvConnected: () => true, + setMpvSubVisibility: (nextVisible) => { + lastBoundSubVisibility = nextVisible; + }, + }, + setInvisibleOverlayVisibleDeps: { + setInvisibleOverlayVisibleCore: (options) => { + setInvisibleCoreCalls += 1; + options.setInvisibleOverlayVisibleState(options.visible); + options.updateInvisibleOverlayVisibility(); + options.syncInvisibleOverlayMousePassthrough(); + }, + setInvisibleOverlayVisibleState: (nextVisible) => { + invisible = nextVisible; + }, + updateInvisibleOverlayVisibility: () => {}, + syncInvisibleOverlayMousePassthrough: () => {}, + }, + getVisibleOverlayVisible: () => visible, + getInvisibleOverlayVisible: () => invisible, + }); + + runtime.setVisibleOverlayVisible(true); + assert.equal(visible, true); + assert.equal(lastBoundSubVisibility, true); + + runtime.toggleVisibleOverlay(); + assert.equal(visible, false); + + runtime.setOverlayVisible(true); + assert.equal(visible, true); + + runtime.toggleOverlay(); + assert.equal(visible, false); + + runtime.setInvisibleOverlayVisible(false); + assert.equal(invisible, false); + + runtime.toggleInvisibleOverlay(); + assert.equal(invisible, true); + + assert.equal(setVisibleCoreCalls, 4); + assert.equal(setInvisibleCoreCalls, 2); +}); diff --git a/src/main/runtime/overlay-visibility-runtime.ts b/src/main/runtime/overlay-visibility-runtime.ts new file mode 100644 index 0000000..9a6db26 --- /dev/null +++ b/src/main/runtime/overlay-visibility-runtime.ts @@ -0,0 +1,78 @@ +import { + createSetInvisibleOverlayVisibleHandler, + createSetVisibleOverlayVisibleHandler, + createToggleInvisibleOverlayHandler, + createToggleVisibleOverlayHandler, +} from './overlay-visibility-actions'; +import { + createBuildSetInvisibleOverlayVisibleMainDepsHandler, + createBuildSetVisibleOverlayVisibleMainDepsHandler, + createBuildToggleInvisibleOverlayMainDepsHandler, + createBuildToggleVisibleOverlayMainDepsHandler, +} from './overlay-visibility-actions-main-deps'; +import { createSetOverlayVisibleHandler, createToggleOverlayHandler } from './overlay-main-actions'; +import { + createBuildSetOverlayVisibleMainDepsHandler, + createBuildToggleOverlayMainDepsHandler, +} from './overlay-main-actions-main-deps'; + +type SetVisibleOverlayVisibleMainDeps = Parameters< + typeof createBuildSetVisibleOverlayVisibleMainDepsHandler +>[0]; +type SetInvisibleOverlayVisibleMainDeps = Parameters< + typeof createBuildSetInvisibleOverlayVisibleMainDepsHandler +>[0]; + +export type OverlayVisibilityRuntimeDeps = { + setVisibleOverlayVisibleDeps: SetVisibleOverlayVisibleMainDeps; + setInvisibleOverlayVisibleDeps: SetInvisibleOverlayVisibleMainDeps; + getVisibleOverlayVisible: () => boolean; + getInvisibleOverlayVisible: () => boolean; +}; + +export function createOverlayVisibilityRuntime(deps: OverlayVisibilityRuntimeDeps) { + const setVisibleOverlayVisibleMainDeps = createBuildSetVisibleOverlayVisibleMainDepsHandler( + deps.setVisibleOverlayVisibleDeps, + )(); + const setVisibleOverlayVisible = createSetVisibleOverlayVisibleHandler( + setVisibleOverlayVisibleMainDeps, + ); + + const setInvisibleOverlayVisibleMainDeps = createBuildSetInvisibleOverlayVisibleMainDepsHandler( + deps.setInvisibleOverlayVisibleDeps, + )(); + const setInvisibleOverlayVisible = createSetInvisibleOverlayVisibleHandler( + setInvisibleOverlayVisibleMainDeps, + ); + + const toggleVisibleOverlayMainDeps = createBuildToggleVisibleOverlayMainDepsHandler({ + getVisibleOverlayVisible: deps.getVisibleOverlayVisible, + setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible), + })(); + const toggleVisibleOverlay = createToggleVisibleOverlayHandler(toggleVisibleOverlayMainDeps); + + const toggleInvisibleOverlayMainDeps = createBuildToggleInvisibleOverlayMainDepsHandler({ + getInvisibleOverlayVisible: deps.getInvisibleOverlayVisible, + setInvisibleOverlayVisible: (visible) => setInvisibleOverlayVisible(visible), + })(); + const toggleInvisibleOverlay = createToggleInvisibleOverlayHandler(toggleInvisibleOverlayMainDeps); + + const setOverlayVisibleMainDeps = createBuildSetOverlayVisibleMainDepsHandler({ + setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible), + })(); + const setOverlayVisible = createSetOverlayVisibleHandler(setOverlayVisibleMainDeps); + + const toggleOverlayMainDeps = createBuildToggleOverlayMainDepsHandler({ + toggleVisibleOverlay: () => toggleVisibleOverlay(), + })(); + const toggleOverlay = createToggleOverlayHandler(toggleOverlayMainDeps); + + return { + setVisibleOverlayVisible, + setInvisibleOverlayVisible, + toggleVisibleOverlay, + toggleInvisibleOverlay, + setOverlayVisible, + toggleOverlay, + }; +}