From b6b81a72f51905533b26b7ddab69ca2f2147eedc Mon Sep 17 00:00:00 2001 From: sudacode Date: Fri, 20 Feb 2026 02:06:42 -0800 Subject: [PATCH] refactor: extract cli command context factory wiring --- docs/subagents/INDEX.md | 2 +- .../codex-task85-20260219T233711Z-46hc.md | 4 ++ src/main.ts | 12 +--- .../cli-command-context-factory.test.ts | 71 +++++++++++++++++++ .../runtime/cli-command-context-factory.ts | 16 +++++ 5 files changed, 95 insertions(+), 10 deletions(-) create mode 100644 src/main/runtime/cli-command-context-factory.test.ts create mode 100644 src/main/runtime/cli-command-context-factory.ts diff --git a/docs/subagents/INDEX.md b/docs/subagents/INDEX.md index 1053adc..b3d17a3 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:04:27Z` | +| `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:06:15Z` | | `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 d315a2f..3ee2702 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:06:15Z] progress: extracted CLI command-context composition from `src/main.ts` into `src/main/runtime/cli-command-context-factory.ts`; `main.ts` now creates context via `createCliCommandContextFactory(...)`. +- [2026-02-20T10:06:15Z] progress: added `src/main/runtime/cli-command-context-factory.test.ts` to validate composed factory behavior. +- [2026-02-20T10:06:15Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + focused suites pass for `cli-command-context-factory*`, `cli-command-context*`, `ipc-runtime-handlers*`, `ipc-bridge-actions*`, `overlay-visibility-runtime*`, and `yomitan-extension-runtime*` (12/12). +- [2026-02-20T10:06:15Z] scope: staging `src/main.ts`, new CLI context factory module/tests, and subagent bookkeeping only. - [2026-02-20T10:04:27Z] progress: extracted IPC bridge composition from `src/main.ts` into `src/main/runtime/ipc-runtime-handlers.ts`; `main.ts` now builds `handleMpvCommandFromIpc` and `runSubsyncManualFromIpc` via one `createIpcRuntimeHandlers(...)` factory. - [2026-02-20T10:04:27Z] progress: added `src/main/runtime/ipc-runtime-handlers.test.ts` for composed IPC handler wiring behavior. - [2026-02-20T10:04:27Z] test: `bun run build` pass (expected macOS helper Swift cache fallback) + focused suites pass for `ipc-runtime-handlers*`, `ipc-bridge-actions*`, `cli-command-context*`, `yomitan-extension-runtime*`, and `overlay-visibility-runtime*` (11/11). diff --git a/src/main.ts b/src/main.ts index 63a6784..d6ce557 100644 --- a/src/main.ts +++ b/src/main.ts @@ -256,7 +256,7 @@ import { createBuildSetFieldGroupingResolverMainDepsHandler, } from './main/runtime/field-grouping-resolver-main-deps'; import { createBuildFieldGroupingOverlayMainDepsHandler } from './main/runtime/field-grouping-overlay-main-deps'; -import { createCliCommandContext } from './main/runtime/cli-command-context'; +import { createCliCommandContextFactory } from './main/runtime/cli-command-context-factory'; import { createBindMpvMainEventHandlersHandler } from './main/runtime/mpv-main-event-bindings'; import { createBuildBindMpvMainEventHandlersMainDepsHandler } from './main/runtime/mpv-main-event-main-deps'; import { createBuildMpvClientRuntimeServiceFactoryDepsHandler } from './main/runtime/mpv-client-runtime-service-main-deps'; @@ -409,8 +409,6 @@ import { import { createYomitanExtensionRuntime } from './main/runtime/yomitan-extension-runtime'; import { createBuildInitializeOverlayRuntimeOptionsHandler } from './main/runtime/overlay-runtime-options'; import { createBuildInitializeOverlayRuntimeMainDepsHandler } from './main/runtime/overlay-runtime-options-main-deps'; -import { createBuildCliCommandContextDepsHandler } from './main/runtime/cli-command-context-deps'; -import { createBuildCliCommandContextMainDepsHandler } from './main/runtime/cli-command-context-main-deps'; import { createOnWillQuitCleanupHandler, createRestoreWindowsOnActivateHandler, @@ -2237,7 +2235,7 @@ const handleTexthookerOnlyModeTransitionHandler = createHandleTexthookerOnlyMode function handleCliCommand(args: CliArgs, source: CliCommandSource = 'initial'): void { handleTexthookerOnlyModeTransitionHandler(args); - const cliContext = createCliCommandContext(buildCliCommandContextDepsHandler()); + const cliContext = createCliCommandContextHandler(); handleCliCommandRuntimeServiceWithContext(args, source, cliContext); } @@ -2961,7 +2959,7 @@ const { handleMpvCommandFromIpc: handleMpvCommandFromIpcHandler, runSubsyncManua runManualFromIpc: (request) => subsyncRuntime.runManualFromIpc(request), }, }); -const buildCliCommandContextMainDepsHandler = createBuildCliCommandContextMainDepsHandler({ +const createCliCommandContextHandler = createCliCommandContextFactory({ appState, texthookerService, getResolvedConfig: () => getResolvedConfig(), @@ -3003,10 +3001,6 @@ const buildCliCommandContextMainDepsHandler = createBuildCliCommandContextMainDe logWarn: (message: string) => logger.warn(message), logError: (message: string, err: unknown) => logger.error(message, err), }); -const cliCommandContextMainDeps = buildCliCommandContextMainDepsHandler(); -const buildCliCommandContextDepsHandler = createBuildCliCommandContextDepsHandler( - cliCommandContextMainDeps, -); const createOverlayWindowHandler = createCreateOverlayWindowHandler( createBuildCreateOverlayWindowMainDepsHandler({ createOverlayWindowCore: (kind, options) => createOverlayWindowCore(kind, options), diff --git a/src/main/runtime/cli-command-context-factory.test.ts b/src/main/runtime/cli-command-context-factory.test.ts new file mode 100644 index 0000000..654dd7d --- /dev/null +++ b/src/main/runtime/cli-command-context-factory.test.ts @@ -0,0 +1,71 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; +import { createCliCommandContextFactory } from './cli-command-context-factory'; + +test('cli command context factory composes main deps and context handlers', () => { + const calls: string[] = []; + const appState = { + mpvSocketPath: '/tmp/mpv.sock', + mpvClient: null as unknown, + texthookerPort: 5174, + overlayRuntimeInitialized: false, + }; + + const createContext = createCliCommandContextFactory({ + appState, + texthookerService: { start: () => null }, + getResolvedConfig: () => ({ texthooker: { openBrowser: true } }), + openExternal: async () => {}, + logBrowserOpenError: () => {}, + showMpvOsd: (text) => calls.push(`osd:${text}`), + initializeOverlayRuntime: () => calls.push('init-overlay'), + toggleVisibleOverlay: () => calls.push('toggle-visible'), + toggleInvisibleOverlay: () => calls.push('toggle-invisible'), + setVisibleOverlayVisible: (visible) => calls.push(`set-visible:${visible}`), + setInvisibleOverlayVisible: (visible) => calls.push(`set-invisible:${visible}`), + copyCurrentSubtitle: () => calls.push('copy-sub'), + startPendingMultiCopy: (timeoutMs) => calls.push(`multi:${timeoutMs}`), + mineSentenceCard: async () => {}, + startPendingMineSentenceMultiple: () => {}, + updateLastCardFromClipboard: async () => {}, + refreshKnownWordCache: async () => {}, + triggerFieldGrouping: async () => {}, + triggerSubsyncFromConfig: async () => {}, + markLastCardAsAudioCard: async () => {}, + getAnilistStatus: () => ({ status: 'ok' }), + clearAnilistToken: () => {}, + openAnilistSetupWindow: () => {}, + openJellyfinSetupWindow: () => {}, + getAnilistQueueStatus: () => ({ queued: 0 }), + processNextAnilistRetryUpdate: async () => ({ ok: true, message: 'ok' }), + runJellyfinCommand: async () => {}, + openYomitanSettings: () => {}, + cycleSecondarySubMode: () => {}, + openRuntimeOptionsPalette: () => {}, + printHelp: () => {}, + stopApp: () => {}, + hasMainWindow: () => true, + getMultiCopyTimeoutMs: () => 5000, + schedule: (fn) => setTimeout(fn, 0), + logInfo: () => {}, + logWarn: () => {}, + logError: () => {}, + }); + + const context = createContext(); + context.setSocketPath('/tmp/new.sock'); + context.showOsd('hello'); + context.setVisibleOverlay(true); + context.setInvisibleOverlay(false); + context.toggleVisibleOverlay(); + context.toggleInvisibleOverlay(); + + assert.equal(appState.mpvSocketPath, '/tmp/new.sock'); + assert.deepEqual(calls, [ + 'osd:hello', + 'set-visible:true', + 'set-invisible:false', + 'toggle-visible', + 'toggle-invisible', + ]); +}); diff --git a/src/main/runtime/cli-command-context-factory.ts b/src/main/runtime/cli-command-context-factory.ts new file mode 100644 index 0000000..0542236 --- /dev/null +++ b/src/main/runtime/cli-command-context-factory.ts @@ -0,0 +1,16 @@ +import { createCliCommandContext } from './cli-command-context'; +import { createBuildCliCommandContextDepsHandler } from './cli-command-context-deps'; +import { createBuildCliCommandContextMainDepsHandler } from './cli-command-context-main-deps'; + +type CliCommandContextMainDeps = Parameters< + typeof createBuildCliCommandContextMainDepsHandler +>[0]; + +export function createCliCommandContextFactory(deps: CliCommandContextMainDeps) { + const buildCliCommandContextMainDepsHandler = createBuildCliCommandContextMainDepsHandler(deps); + const cliCommandContextMainDeps = buildCliCommandContextMainDepsHandler(); + const buildCliCommandContextDepsHandler = + createBuildCliCommandContextDepsHandler(cliCommandContextMainDeps); + + return () => createCliCommandContext(buildCliCommandContextDepsHandler()); +}