refactor: extract overlay visibility runtime wiring

This commit is contained in:
2026-02-20 02:02:52 -08:00
parent 3aeb10ae61
commit 5b432fa156
5 changed files with 191 additions and 83 deletions

View File

@@ -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-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-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-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-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` | | `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` |

View File

@@ -9,6 +9,10 @@
## Current Work (newest first) ## 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: 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] 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). - [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).

View File

@@ -354,30 +354,15 @@ import {
createBuildHandleMineSentenceDigitMainDepsHandler, createBuildHandleMineSentenceDigitMainDepsHandler,
createBuildHandleMultiCopyDigitMainDepsHandler, createBuildHandleMultiCopyDigitMainDepsHandler,
} from './main/runtime/mining-actions-main-deps'; } 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 { createBuildOverlayVisibilityRuntimeMainDepsHandler } from './main/runtime/overlay-visibility-runtime-main-deps';
import { createOverlayVisibilityRuntime } from './main/runtime/overlay-visibility-runtime';
import { import {
createAppendClipboardVideoToQueueHandler, createAppendClipboardVideoToQueueHandler,
createHandleOverlayModalClosedHandler, createHandleOverlayModalClosedHandler,
createSetOverlayVisibleHandler,
createToggleOverlayHandler,
} from './main/runtime/overlay-main-actions'; } from './main/runtime/overlay-main-actions';
import { import {
createBuildAppendClipboardVideoToQueueMainDepsHandler, createBuildAppendClipboardVideoToQueueMainDepsHandler,
createBuildHandleOverlayModalClosedMainDepsHandler, createBuildHandleOverlayModalClosedMainDepsHandler,
createBuildSetOverlayVisibleMainDepsHandler,
createBuildToggleOverlayMainDepsHandler,
} from './main/runtime/overlay-main-actions-main-deps'; } from './main/runtime/overlay-main-actions-main-deps';
import { import {
createBroadcastRuntimeOptionsChangedHandler, createBroadcastRuntimeOptionsChangedHandler,
@@ -2885,77 +2870,44 @@ const handleMineSentenceDigitMainDeps = buildHandleMineSentenceDigitMainDepsHand
const handleMineSentenceDigitHandler = createHandleMineSentenceDigitHandler( const handleMineSentenceDigitHandler = createHandleMineSentenceDigitHandler(
handleMineSentenceDigitMainDeps, handleMineSentenceDigitMainDeps,
); );
const buildSetVisibleOverlayVisibleMainDepsHandler = const {
createBuildSetVisibleOverlayVisibleMainDepsHandler({ setVisibleOverlayVisible: setVisibleOverlayVisibleHandler,
setVisibleOverlayVisibleCore, setInvisibleOverlayVisible: setInvisibleOverlayVisibleHandler,
setVisibleOverlayVisibleState: (nextVisible) => { toggleVisibleOverlay: toggleVisibleOverlayHandler,
overlayManager.setVisibleOverlayVisible(nextVisible); 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(), setInvisibleOverlayVisibleDeps: {
updateInvisibleOverlayVisibility: () => overlayVisibilityRuntime.updateInvisibleOverlayVisibility(), setInvisibleOverlayVisibleCore,
syncInvisibleOverlayMousePassthrough: () => setInvisibleOverlayVisibleState: (nextVisible) => {
overlayVisibilityRuntime.syncInvisibleOverlayMousePassthrough(), overlayManager.setInvisibleOverlayVisible(nextVisible);
shouldBindVisibleOverlayToMpvSubVisibility: () => },
configDerivedRuntime.shouldBindVisibleOverlayToMpvSubVisibility(), updateInvisibleOverlayVisibility: () =>
isMpvConnected: () => Boolean(appState.mpvClient && appState.mpvClient.connected), overlayVisibilityRuntime.updateInvisibleOverlayVisibility(),
setMpvSubVisibility: (mpvSubVisible) => { syncInvisibleOverlayMousePassthrough: () =>
setMpvSubVisibilityRuntime(appState.mpvClient, mpvSubVisible); 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(), getVisibleOverlayVisible: () => overlayManager.getVisibleOverlayVisible(),
setVisibleOverlayVisible: (visible) => setVisibleOverlayVisible(visible),
});
const toggleVisibleOverlayMainDeps = buildToggleVisibleOverlayMainDepsHandler();
const toggleVisibleOverlayHandler = createToggleVisibleOverlayHandler(
toggleVisibleOverlayMainDeps,
);
const buildToggleInvisibleOverlayMainDepsHandler =
createBuildToggleInvisibleOverlayMainDepsHandler({
getInvisibleOverlayVisible: () => overlayManager.getInvisibleOverlayVisible(), 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 = const buildHandleOverlayModalClosedMainDepsHandler =
createBuildHandleOverlayModalClosedMainDepsHandler({ createBuildHandleOverlayModalClosedMainDepsHandler({

View File

@@ -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);
});

View File

@@ -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,
};
}