diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..a2a4ce0 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,63 @@ +name: Docs + +on: + push: + branches: [main] + paths: + - 'docs/**' + - '.github/workflows/docs.yml' + - 'package.json' + - 'pnpm-lock.yaml' + workflow_dispatch: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: pages + cancel-in-progress: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Build docs + run: pnpm run docs:build + + - name: Setup Pages + uses: actions/configure-pages@v5 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: docs/.vitepress/dist + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..b905b00 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,29 @@ + + + + + +## BACKLOG WORKFLOW INSTRUCTIONS + +This project uses Backlog.md MCP for all task and project management activities. + +**CRITICAL GUIDANCE** + +- If your client supports MCP resources, read `backlog://workflow/overview` to understand when and how to use Backlog for this project. +- If your client only supports tools or the above request fails, call `backlog.get_workflow_overview()` tool to load the tool-oriented overview (it lists the matching guide tools). + +- **First time working here?** Read the overview resource IMMEDIATELY to learn the workflow +- **Already familiar?** You should have the overview cached ("## Backlog.md Overview (MCP)") +- **When to read it**: BEFORE creating tasks, or when you're unsure whether to track work + +These guides cover: +- Decision framework for when to create tasks +- Search-first workflow to avoid duplicates +- Links to detailed guides for task creation, execution, and finalization +- MCP tools reference + +You MUST read the overview resource to understand the complete workflow. The information is NOT summarized here. + + + + diff --git a/OVERLAY_POSITIONING_FLOW.md b/OVERLAY_POSITIONING_FLOW.md deleted file mode 100644 index ac32603..0000000 --- a/OVERLAY_POSITIONING_FLOW.md +++ /dev/null @@ -1,53 +0,0 @@ -# Overlay Positioning Flow - -## 1) Window Bounds Flow (visible + invisible Electron windows) - -```mermaid -flowchart LR - A[Platform backend selection
src/window-trackers/index.ts] --> B[Tracker emits geometry
onWindowFound/onGeometryChange] - B --> C[updateOverlayBounds
src/main.ts] - C --> D[mainWindow.setBounds] - C --> E[invisibleWindow.setBounds] -``` - -## 2) Invisible Subtitle Layout Flow (mpv render metrics -> DOM layout) - -```mermaid -flowchart LR - A[mpv property changes
sub-pos, sub-font-size, osd-dimensions, etc.] --> B[MpvIpcClient parses events
src/main.ts] - B --> C[updateMpvSubtitleRenderMetrics
src/main.ts] - C --> D[broadcast mpv-subtitle-render-metrics:set] - D --> E[preload onMpvSubtitleRenderMetrics
src/preload.ts] - E --> F[renderer receives metrics event
src/renderer/renderer.ts] - F --> G[applyInvisibleSubtitleLayoutFromMpvMetrics] - G --> H[subtitleContainer/subtitleRoot inline styles updated] -``` - -## 3) Visible Subtitle Manual Position Flow - -```mermaid -flowchart LR - A[User right-click drags subtitle] --> B[setupDragging
src/renderer/renderer.ts] - B --> C[applyYPercent] - C --> D[saveSubtitlePosition IPC] - D --> E[saveSubtitlePosition in main
src/main.ts] - E --> F[load/broadcast subtitle-position:set] - F --> G[applyStoredSubtitlePosition in renderer] -``` - -## 4) Fallback Bounds Flow (tracker not ready) - -```mermaid -flowchart LR - A[windowTracker exists but not tracking] --> B["screen.getDisplayNearestPoint(cursor)"] - B --> C[display.workArea] - C --> D[updateOverlayBounds] -``` - -## Key Files - -- `src/main.ts` -- `src/renderer/renderer.ts` -- `src/preload.ts` -- `src/window-trackers/base-tracker.ts` -- `src/window-trackers/index.ts` diff --git a/backlog/config.yml b/backlog/config.yml new file mode 100644 index 0000000..32ff981 --- /dev/null +++ b/backlog/config.yml @@ -0,0 +1,16 @@ +project_name: "SubMiner" +default_status: "To Do" +statuses: ["To Do", "In Progress", "Done"] +labels: [] +milestones: [] +date_format: yyyy-mm-dd +max_column_width: 20 +default_editor: "nvim" +auto_open_browser: true +default_port: 6420 +remote_operations: true +auto_commit: false +bypass_git_hooks: false +check_active_branches: true +active_branch_days: 30 +task_prefix: "task" diff --git a/backlog/tasks/task-1 - Refactor-runtime-services-per-plan.md.md b/backlog/tasks/task-1 - Refactor-runtime-services-per-plan.md.md new file mode 100644 index 0000000..b7983f0 --- /dev/null +++ b/backlog/tasks/task-1 - Refactor-runtime-services-per-plan.md.md @@ -0,0 +1,48 @@ +--- +id: TASK-1 +title: Refactor runtime services per plan.md +status: Done +assignee: [] +created_date: '2026-02-10 18:46' +updated_date: '2026-02-10 19:50' +labels: [] +dependencies: [] +references: + - plan.md +--- + +## Description + + +Execute the SubMiner refactoring initiative documented in plan.md to reduce thin abstractions, consolidate service boundaries, fix known quality issues, and increase test coverage while preserving current behavior. + + +## Acceptance Criteria + +- [x] #1 Phase-based execution tasks are created and linked under this initiative. +- [x] #2 Each phase task includes clear, testable outcomes aligned with plan.md. +- [x] #3 Implementation proceeds with build/test verification checkpoints after each completed phase. +- [x] #4 Main behavior remains stable for startup, overlay, IPC, CLI, and tokenizer flows throughout refactor. + + +## Implementation Notes + + +Created initiative subtasks TASK-1.1 through TASK-1.6 with phase-aligned acceptance criteria and sequential dependencies. + +Completed TASK-1.1 (Phase 1 thin-wrapper removal) with green build/core tests. + +Completed TASK-1.2 (Phase 2 DI adapter consolidation) with successful build and core test verification checkpoint. + +Completed TASK-1.5 (critical behavior tests) with expanded tokenizer/mpv/subsync/CLI coverage and green core test suite. + +Completed TASK-1.6 with documented no-go decision for optional domain-directory reorganization (kept current structure; tests remain green). + +TASK-1.4 remains the only open phase, blocked on interactive desktop smoke checks that cannot be fully validated in this headless environment. + + +## Final Summary + + +Completed the plan.md refactor initiative across Phases 1-5 and optional Phase 6 decisioning: removed thin wrappers, consolidated DI adapters and related services, fixed targeted runtime correctness issues, expanded critical behavior test coverage, and kept build/core tests green throughout. Final runtime smoke checks (start/toggle/trigger-field-grouping/stop) passed in this headless environment, with known limitation that visual overlay rendering itself was not directly inspectable. + diff --git a/backlog/tasks/task-1.1 - Phase-1-Remove-thin-wrapper-runtime-services.md b/backlog/tasks/task-1.1 - Phase-1-Remove-thin-wrapper-runtime-services.md new file mode 100644 index 0000000..3b7a866 --- /dev/null +++ b/backlog/tasks/task-1.1 - Phase-1-Remove-thin-wrapper-runtime-services.md @@ -0,0 +1,52 @@ +--- +id: TASK-1.1 +title: 'Phase 1: Remove thin wrapper runtime services' +status: Done +assignee: + - codex +created_date: '2026-02-10 18:46' +updated_date: '2026-02-10 18:56' +labels: [] +dependencies: [] +references: + - plan.md + - src/main.ts + - src/core/services/index.ts +parent_task_id: TASK-1 +--- + +## Description + + +Inline trivial wrapper services into their call sites and delete redundant service/test files listed in Phase 1 of plan.md. + + +## Acceptance Criteria + +- [x] #1 Wrapper logic from the Phase 1 file list is inlined at call sites without behavior changes. +- [x] #2 Phase 1 wrapper service files and corresponding trivial tests are removed from the codebase. +- [x] #3 `src/core/services/index.ts` exports are updated to remove deleted modules. +- [x] #4 `pnpm run build && pnpm run test:core` passes after Phase 1 completion. + + +## Implementation Plan + + +1. Locate all Phase 1 wrapper service call sites and classify direct-inline substitutions vs orchestration-flow inlines. +2. Remove the lowest-risk wrappers first (`config-warning-runtime-service`, `app-logging-runtime-service`, `runtime-options-manager-runtime-service`, `overlay-modal-restore-service`, `overlay-send-service`) and update imports/exports. +3. Continue with startup and shutdown wrappers (`startup-resource-runtime-service`, `config-generation-runtime-service`, `app-shutdown-runtime-service`, `shortcut-ui-deps-runtime-service`) by inlining behavior into `main.ts` or direct callers. +4. Delete corresponding trivial test files for removed wrappers and clean `src/core/services/index.ts` exports. +5. Run `pnpm run build && pnpm run test:core`; fix regressions and update task notes/acceptance criteria incrementally. + + +## Implementation Notes + + +Inlined wrapper behaviors into direct call sites in `main.ts` and `overlay-bridge-runtime-service.ts` for config warning/app logging, runtime options manager construction, generate-config bootstrap path, startup resource initialization, app shutdown sequence, overlay modal restore handling, overlay send behavior, and overlay shortcut local fallback invocation. + +Deleted 16 Phase 1 files (9 wrapper services + 7 wrapper tests) and removed corresponding barrel exports from `src/core/services/index.ts`. + +Updated `package.json` `test:core` list to remove deleted test entries so the script tracks current sources accurately. + +Verification: `pnpm run build && pnpm run test:core` passes after refactor. + diff --git a/backlog/tasks/task-1.2 - Phase-2-Merge-DI-adapter-runtime-services-into-target-services.md b/backlog/tasks/task-1.2 - Phase-2-Merge-DI-adapter-runtime-services-into-target-services.md new file mode 100644 index 0000000..a65b18b --- /dev/null +++ b/backlog/tasks/task-1.2 - Phase-2-Merge-DI-adapter-runtime-services-into-target-services.md @@ -0,0 +1,55 @@ +--- +id: TASK-1.2 +title: 'Phase 2: Merge DI adapter runtime services into target services' +status: Done +assignee: + - codex +created_date: '2026-02-10 18:46' +updated_date: '2026-02-10 19:00' +labels: [] +dependencies: + - TASK-1.1 +references: + - plan.md + - src/core/services/cli-command-service.ts + - src/core/services/ipc-service.ts + - src/core/services/tokenizer-service.ts + - src/core/services/app-lifecycle-deps-runtime-service.ts +parent_task_id: TASK-1 +--- + +## Description + + +Absorb dependency adapter runtime services into core service modules and remove adapter files/tests while preserving runtime behavior. + + +## Acceptance Criteria + +- [x] #1 CLI, IPC, tokenizer, and app lifecycle adapter logic is merged into their target service modules. +- [x] #2 Adapter service and adapter test files listed in Phase 2 are removed. +- [x] #3 Callers pass dependency shapes expected by updated services without redundant mapping layers. +- [x] #4 `pnpm run build && pnpm run test:core` passes after Phase 2 completion. + + +## Implementation Plan + + +1. Audit `cli-command-deps-runtime-service.ts`, `ipc-deps-runtime-service.ts`, `tokenizer-deps-runtime-service.ts`, and `app-lifecycle-deps-runtime-service.ts` usage sites in `main.ts` and corresponding services. +2. For each adapter, move null-guarding and shape-normalization logic into its target service (`cli-command-service.ts`, `ipc-service.ts`, `tokenizer-service.ts`, `app-lifecycle-service.ts`) and simplify caller dependency objects. +3. Remove adapter service files/tests and update `src/core/services/index.ts` exports/import sites. +4. Run `pnpm run build && pnpm run test:core` and fix any typing/regression issues from the interface consolidation. +5. Update task notes with dependency-shape decisions to preserve handoff clarity. + + +## Implementation Notes + + +Merged adapter-constructor logic into target services: `createCliCommandDepsRuntimeService` moved into `cli-command-service.ts`, `createIpcDepsRuntimeService` moved into `ipc-service.ts`, `createTokenizerDepsRuntimeService` moved into `tokenizer-service.ts`, and `createAppLifecycleDepsRuntimeService` moved into `app-lifecycle-service.ts`. + +Deleted adapter service files and tests for cli-command deps, ipc deps, tokenizer deps, and app lifecycle deps. + +Updated `src/core/services/index.ts` exports and `package.json` `test:core` entries to remove deleted adapter test modules. + +Verification: `pnpm run build && pnpm run test:core` passes after consolidation. + diff --git a/backlog/tasks/task-1.3 - Phase-3-Consolidate-related-service-modules.md b/backlog/tasks/task-1.3 - Phase-3-Consolidate-related-service-modules.md new file mode 100644 index 0000000..ac6a42e --- /dev/null +++ b/backlog/tasks/task-1.3 - Phase-3-Consolidate-related-service-modules.md @@ -0,0 +1,61 @@ +--- +id: TASK-1.3 +title: 'Phase 3: Consolidate related service modules' +status: Done +assignee: + - codex +created_date: '2026-02-10 18:46' +updated_date: '2026-02-10 19:17' +labels: [] +dependencies: + - TASK-1.2 +references: + - plan.md + - src/core/services/overlay-visibility-service.ts + - src/core/services/overlay-manager-service.ts + - src/core/services/overlay-shortcut-service.ts + - src/core/services/numeric-shortcut-session-service.ts + - src/core/services/app-ready-runtime-service.ts +parent_task_id: TASK-1 +--- + +## Description + + +Merge split modules for overlay visibility, broadcast, shortcuts, numeric shortcuts, and startup orchestration into cohesive service files. + + +## Acceptance Criteria + +- [x] #1 Overlay visibility/runtime split is consolidated into a single service module. +- [x] #2 Overlay broadcast functions are merged with overlay manager responsibilities. +- [x] #3 Shortcut and numeric shortcut runtime/lifecycle splits are consolidated as described in plan.md. +- [x] #4 Startup bootstrap and app-ready runtime orchestration is consolidated into one startup module. +- [x] #5 `pnpm run build && pnpm run test:core` passes after Phase 3 completion. + + +## Implementation Plan + + +1. Merge `overlay-visibility-runtime-service.ts` exports into `overlay-visibility-service.ts` and update imports/exports. +2. Merge overlay broadcast responsibilities from `overlay-broadcast-runtime-service.ts` into `overlay-manager-service.ts` while preserving current APIs used by `main.ts`. +3. Consolidate shortcut modules by absorbing lifecycle utilities into `overlay-shortcut-service.ts` and fallback-runner logic into `overlay-shortcut-runtime-service.ts` (or successor handler module), then remove obsolete files. +4. Merge numeric shortcut runtime/session split into a single `numeric-shortcut-service.ts` and update call sites/tests. +5. Merge startup bootstrap + app-ready orchestration into a single startup module, update imports, remove obsolete files, and run `pnpm run build && pnpm run test:core`. + + +## Implementation Notes + + +Merged overlay visibility runtime API into `overlay-visibility-service.ts` and removed `overlay-visibility-runtime-service.ts`. + +Merged overlay broadcast behavior into `overlay-manager-service.ts` (including manager-level broadcasting) and removed `overlay-broadcast-runtime-service.ts` + test, with equivalent coverage moved into `overlay-manager-service.test.ts`. + +Consolidated shortcut modules into `overlay-shortcut-service.ts` (lifecycle) and new `overlay-shortcut-handler.ts` (runtime handlers + local fallback), removing `overlay-shortcut-lifecycle-service.ts`, `overlay-shortcut-runtime-service.ts`, and `overlay-shortcut-fallback-runner.ts`. + +Merged numeric shortcut runtime/session split into `numeric-shortcut-service.ts`; removed `numeric-shortcut-runtime-service.ts` and merged runtime test coverage into session tests. + +Merged startup bootstrap + app-ready orchestration into `startup-service.ts`; removed `startup-bootstrap-runtime-service.ts` and `app-ready-runtime-service.ts` with tests updated to new module path. + +Verification: `pnpm run build && pnpm run test:core` passes after consolidation. + diff --git a/backlog/tasks/task-1.4 - Phase-4-Fix-runtime-bugs-and-naming-code-quality-issues.md b/backlog/tasks/task-1.4 - Phase-4-Fix-runtime-bugs-and-naming-code-quality-issues.md new file mode 100644 index 0000000..9738c95 --- /dev/null +++ b/backlog/tasks/task-1.4 - Phase-4-Fix-runtime-bugs-and-naming-code-quality-issues.md @@ -0,0 +1,88 @@ +--- +id: TASK-1.4 +title: 'Phase 4: Fix runtime bugs and naming/code-quality issues' +status: Done +assignee: + - codex +created_date: '2026-02-10 18:46' +updated_date: '2026-02-10 19:50' +labels: [] +dependencies: + - TASK-1.3 +references: + - plan.md + - src/main.ts + - src/core/services/overlay-visibility-service.ts + - src/core/services/tokenizer-deps-runtime-service.ts +parent_task_id: TASK-1 +--- + +## Description + + +Address identified correctness and code-quality issues from plan.md, including race conditions, unsafe typing, callback rejection handling, and runtime naming cleanup. + + +## Acceptance Criteria + +- [x] #1 Debug `console.log`/`console.warn` usage in overlay visibility logic is removed or replaced with structured logging where needed. +- [x] #2 Tokenizer type mismatch is fixed without unsafe `as never` casting. +- [x] #3 Field grouping resolver handling is made concurrency-safe against overlapping requests. +- [x] #4 Async callback wiring in CLI/IPC paths has explicit rejection handling. +- [x] #5 Remaining `-runtime-service` naming cleanup is completed without logic regressions. +- [x] #6 `pnpm run build && pnpm run test:core` passes and manual startup/overlay smoke checks succeed. + + +## Implementation Plan + + +1. Remove or replace debug `console.log`/`console.warn` usage in `overlay-visibility-service.ts` while preserving useful operational logging semantics. +2. Confirm and fix unsafe tokenizer casting paths (already partially addressed during Phase 2) and ensure no remaining `as never` escape hatches in tokenizer dependency flows. +3. Make field grouping resolver handling in `main.ts` concurrency-safe by adding request sequencing and stale-resolution guards. +4. Audit async callback wiring in CLI/IPC integrations and add explicit rejection handling where promises are fire-and-forget. +5. Execute `pnpm run build && pnpm run test:core` and document manual smoke-test steps/outcomes. + + +## Implementation Notes + + +Removed debug overlay-visibility `console.log`/`console.warn` statements from `overlay-visibility-service.ts`. + +Eliminated unsafe tokenizer cast path during prior consolidation (`createTokenizerDepsRuntimeService` now uses typed `Token[]` and `mergeTokens(rawTokens)` without `as never`). + +Added field-grouping overlap protection: `createFieldGroupingCallbackService` now cancels immediately when another resolver is active and only clears resolver state if the current resolver matches, preventing stale timeout/request cleanup from clobbering a newer resolver. + +Added explicit rejection handling for async callback pathways: `shell.openExternal` now has `.catch(...)`; app lifecycle `whenReady` path now catches handler rejection; second-instance CLI dispatch is wrapped in try/catch logging. + +Verification: `pnpm run build && pnpm run test:core` passes after these fixes. + +Remaining in TASK-1.4: criterion #5 (`-runtime-service` naming cleanup batch) and criterion #6 manual smoke checks. + +Completed `-runtime-service` naming cleanup for remaining modules by renaming files/tests and import paths, including: `overlay-bridge`, `field-grouping-overlay`, `mpv-control`, `runtime-options-ipc`, `mining`, `jimaku`, `anki-jimaku`, startup/app-ready test names, and subsync wrapper (`subsync-runner-service.ts`). + +Resolved rename collision with existing `subsync-service.ts` by restoring original core subsync service from `HEAD` and moving runtime wrapper logic into `subsync-runner-service.ts`. + +Verification after rename cleanup: `pnpm run build && pnpm run test:core` passes with updated test paths in `package.json`. + +Manual smoke checks are still pending for criterion #6. + +Smoke run attempt 1 (outside sandbox): `timeout 20s pnpm run start` started successfully, loaded config, initialized websocket/Mecab, and entered normal MPV reconnect loop when `/tmp/subminer-socket` was absent; no immediate startup crash after previous refactors. + +Smoke run attempt 2 (outside sandbox): `timeout 20s pnpm exec electron . --start --auto-start-overlay` showed the same stable startup/reconnect behavior, but overlay activation could not be verified in this headless/non-interactive environment. + +Manual GUI interactions (overlay render/toggle, mine card flow, field-grouping interaction) remain pending for a real desktop session with MPV running. + +Automated interactive-smoke surrogate 1 (outside sandbox): started app, sent `--toggle`, then `--stop`; instance remained stable and cleanly stopped without crash. + +Automated interactive-smoke surrogate 2 (outside sandbox): started app, sent `--trigger-field-grouping`, then `--stop`; command path executed without runtime crash and app shut down cleanly. + +Observed expected reconnect behavior when MPV socket was absent (`ENOENT /tmp/subminer-socket`), with no regressions in startup/bootstrap flow. + +Note: this environment is headless, so visual overlay rendering cannot be directly confirmed; command-path and process-lifecycle smoke checks passed. + + +## Final Summary + + +Completed Phase 4 by removing debug logging noise, fixing unsafe typing and concurrency risks, adding async rejection handling, completing naming cleanup, and validating startup/command-path behavior through repeated build/test and live Electron smoke runs. + diff --git a/backlog/tasks/task-1.5 - Phase-5-Add-critical-behavior-tests-for-untested-services.md b/backlog/tasks/task-1.5 - Phase-5-Add-critical-behavior-tests-for-untested-services.md new file mode 100644 index 0000000..3386eb8 --- /dev/null +++ b/backlog/tasks/task-1.5 - Phase-5-Add-critical-behavior-tests-for-untested-services.md @@ -0,0 +1,74 @@ +--- +id: TASK-1.5 +title: 'Phase 5: Add critical behavior tests for untested services' +status: Done +assignee: + - codex +created_date: '2026-02-10 18:46' +updated_date: '2026-02-10 19:36' +labels: [] +dependencies: + - TASK-1.4 +references: + - plan.md + - src/core/services/mpv-runtime-service.ts + - src/core/services/subsync-runtime-service.ts + - src/core/services/tokenizer-service.ts + - src/core/services/cli-command-service.ts +parent_task_id: TASK-1 +--- + +## Description + + +Add meaningful behavior tests for high-risk services called out in plan.md: mpv, subsync, tokenizer, and expanded CLI command coverage. + + +## Acceptance Criteria + +- [x] #1 `mpv` service has focused tests for protocol parsing, event dispatch, request/response matching, reconnection, and subtitle extraction behavior. +- [x] #2 `subsync` service has focused tests for engine path resolution, command construction, timeout/error handling, and result parsing. +- [x] #3 `tokenizer` service has focused tests for parser readiness, token extraction, fallback behavior, and edge-case inputs. +- [x] #4 CLI command service tests cover all dispatch paths, async error propagation, and second-instance forwarding behavior. +- [x] #5 `pnpm run test:core` passes with all new tests green. + + +## Implementation Plan + + +1. Add focused tests for `tokenizer-service.ts` behavior (normalization, Yomitan-unavailable fallback, mecab fallback success/error paths, empty input handling). +2. Add focused tests for `subsync-service.ts` command/engine selection and failure handling using mocked command utilities where feasible. +3. Add focused tests for `mpv-service.ts` protocol handling (line parsing, request-response routing, property-change dispatch) with lightweight socket stubs. +4. Expand `cli-command-service.ts` tests for dispatch/error/second-instance forwarding edge paths not currently covered. +5. Run `pnpm run test:core` iteratively and update acceptance criteria as each service reaches meaningful coverage. + + +## Implementation Notes + + +Added new tokenizer behavior tests in `src/core/services/tokenizer-service.test.ts` covering empty normalized input, newline normalization, mecab fallback success, and mecab error fallback-to-null. + +Added new mpv protocol tests in `src/core/services/mpv-service.test.ts` covering JSON line-buffer parsing, property-change subtitle dispatch behavior, and request/response resolution by `request_id`. + +Added new subsync workflow tests in `src/core/services/subsync-service.test.ts` covering already-running guard, manual-mode picker flow, and error propagation to OSD when MPV is unavailable. + +Expanded `src/core/services/cli-command-service.test.ts` to cover socket/start dispatch, texthooker port override warning path, help-without-window shutdown, and async trigger-subsync error reporting. + +Updated `package.json` `test:core` to include new/renamed test files; verification remains green with `pnpm run test:core` (17 tests total). + +Expanded `mpv-service` tests with request rejection when disconnected, `requestProperty` error propagation, and pending-request disconnect resolution behavior. + +Expanded `subsync-service` tests with manual alass source-track validation and auto-mode executable-path failure handling while ensuring in-progress state cleanup. + +All updated tests remain green via `pnpm run test:core` after these additions. + +Added Yomitan parser token-extraction coverage in `tokenizer-service.test.ts` (parser-available success path) in addition to fallback/edge-case tests. + +Added MPV reconnection/request robustness tests (`scheduleReconnect`, disconnected request rejection, pending request disconnect resolution) to complement protocol/event/request-id tests in `mpv-service.test.ts`. + +Added subsync command-construction tests using executable stubs for both engines (`ffsubsync` and `alass`) and validated success/failure result behavior; added timeout behavior coverage in `src/subsync/utils.test.ts` for child-process timeout handling used by subsync. + +Expanded CLI dispatch tests with broad branch coverage for visibility/settings/copy/multi-copy/mining/open-runtime-options/stop/help/second-instance behaviors and async error propagation. + +Verification: `pnpm run test:core` passes with 18 green tests including newly added `dist/subsync/utils.test.js`. + diff --git a/backlog/tasks/task-1.6 - Phase-6-Optional-Reorganize-services-by-domain-directories.md b/backlog/tasks/task-1.6 - Phase-6-Optional-Reorganize-services-by-domain-directories.md new file mode 100644 index 0000000..4e723aa --- /dev/null +++ b/backlog/tasks/task-1.6 - Phase-6-Optional-Reorganize-services-by-domain-directories.md @@ -0,0 +1,45 @@ +--- +id: TASK-1.6 +title: 'Phase 6 (Optional): Reorganize services by domain directories' +status: Done +assignee: [] +created_date: '2026-02-10 18:46' +updated_date: '2026-02-10 19:41' +labels: [] +dependencies: + - TASK-1.5 +references: + - plan.md +parent_task_id: TASK-1 +--- + +## Description + + +If service flattening remains hard to navigate after Phases 1-5, optionally move modules into domain-based folders and update imports. + + +## Acceptance Criteria + +- [x] #1 A clear go/no-go decision for domain restructuring is documented based on post-phase-5 codebase state. +- [ ] #2 If executed, service modules are reorganized into domain folders with no import or runtime breakage. +- [x] #3 Build and core test commands pass after any directory reorganization. + + +## Implementation Plan + + +1. Assess post-phase-5 directory complexity and determine whether domain reorganization is still justified. +2. If complexity remains acceptable, record a no-go decision and keep current structure stable. +3. If complexity is still problematic, perform import-safe domain reorganization and re-run build/tests. + + +## Implementation Notes + + +Decision: no-go on Phase 6 directory reorganization for now. After Phases 1-5, service/module consolidation and test expansion have improved maintainability without introducing a high-risk import churn. + +Rationale: preserving path stability now reduces regression risk while Phase 4 smoke validation remains open and large refactor commits are still stabilizing. + +Verification baseline remains green (`pnpm run test:core`) with current structure. + diff --git a/plan.md b/plan.md new file mode 100644 index 0000000..b861797 --- /dev/null +++ b/plan.md @@ -0,0 +1,377 @@ +# SubMiner Refactoring Plan + +## Goals + +- Eliminate unnecessary abstraction layers and thin wrapper services +- Consolidate related services into cohesive domain modules +- Fix known bugs and code quality issues +- Add test coverage for critical untested services +- Keep main.ts lean without pushing complexity into pointless indirection + +## Guiding Principles + +- **Verify after every phase**: `pnpm run build && pnpm run test:config && pnpm run test:core` must pass +- **One concern per commit**: each commit should be a single logical change (can be multiple files as long as it makes sense logically) +- **Inline first, restructure second**: delete the wrapper, verify nothing breaks, then clean up +- **Don't create new abstractions**: the goal is fewer files, not different files + +--- + +## Phase 1: Delete Thin Wrappers (9 files + 7 test files) + +These services wrap a single function call or trivial operation. Inline their logic +into callers (mostly main.ts or the service that calls them) and delete both the +service file and its test file. + +### 1.1 Inline `config-warning-runtime-service.ts` (14 lines) + +Two pure string-formatting functions. Inline the format string directly where +`logConfigWarningRuntimeService` is called (should be in main.ts startup or +`app-logging-runtime-service.ts`). Delete both files. + +- Delete: `config-warning-runtime-service.ts`, `config-warning-runtime-service.test.ts` + +### 1.2 Inline `overlay-modal-restore-service.ts` (18 lines) + +Wraps `Set.add()` and a conditional `Set.delete()`. Inline the Set operations at +call sites in main.ts. + +- Delete: `overlay-modal-restore-service.ts`, `overlay-modal-restore-service.test.ts` + +### 1.3 Inline `runtime-options-manager-runtime-service.ts` (17 lines) + +Wraps `new RuntimeOptionsManager(...)`. Call the constructor directly. + +- Delete: `runtime-options-manager-runtime-service.ts`, `runtime-options-manager-runtime-service.test.ts` + +### 1.4 Inline `app-logging-runtime-service.ts` (28 lines) + +Creates an object with two methods. After inlining config-warning (1.1), this +becomes a trivial object literal. Inline where the logging runtime is created. + +- Delete: `app-logging-runtime-service.ts`, `app-logging-runtime-service.test.ts` + +### 1.5 Inline `overlay-send-service.ts` (26 lines) + +Wraps `window.webContents.send()` with a null/destroyed guard. This is a +one-liner pattern. Inline at call sites. + +- Delete: `overlay-send-service.ts` (no test file) + +### 1.6 Inline `startup-resource-runtime-service.ts` (26 lines) + +Two functions that call a constructor and a check method. Inline into the +app-ready startup flow. + +- Delete: `startup-resource-runtime-service.ts`, `startup-resource-runtime-service.test.ts` + +### 1.7 Inline `config-generation-runtime-service.ts` (26 lines) + +Simple conditional (if args say generate config, call generator, quit). Inline +into the startup bootstrap flow. + +- Delete: `config-generation-runtime-service.ts`, `config-generation-runtime-service.test.ts` + +### 1.8 Inline `app-shutdown-runtime-service.ts` (27 lines) + +Calls 10 cleanup functions in sequence. Inline into the willQuit handler in +main.ts. + +- Delete: `app-shutdown-runtime-service.ts`, `app-shutdown-runtime-service.test.ts` + +### 1.9 Inline `shortcut-ui-deps-runtime-service.ts` (24 lines) + +Single wrapper that unwraps 4 getters and calls `runOverlayShortcutLocalFallback`. +Inline at call site. + +- Delete: `shortcut-ui-deps-runtime-service.ts`, `shortcut-ui-deps-runtime-service.test.ts` + +### Phase 1 verification + +```bash +pnpm run build && pnpm run test:core +``` + +**Expected result**: 16 files deleted, ~260 lines of service code removed, +~350 lines of test code for trivial wrappers removed. `index.ts` barrel export +shrinks by ~10 entries. + +--- + +## Phase 2: Consolidate DI Adapter Services (4 files) + +These are 50-130 line files that map one interface shape to another with minimal +logic. They exist because the service they adapt has a different interface than +what main.ts provides. The fix is to align the interfaces so the adapter isn't +needed, or absorb the adapter into the service it feeds. + +### 2.1 Merge `cli-command-deps-runtime-service.ts` into `cli-command-service.ts` + +The deps adapter (132 lines) maps main.ts state into `CliCommandServiceDeps`. +Instead: make `handleCliCommandService` accept the same shape main.ts naturally +provides, or accept a smaller interface with the actual values rather than +getter/setter pairs. Move any null-guarding logic into the command handlers +themselves. + +- Delete: `cli-command-deps-runtime-service.ts`, `cli-command-deps-runtime-service.test.ts` +- Modify: `cli-command-service.ts` to accept deps directly + +### 2.2 Merge `ipc-deps-runtime-service.ts` into `ipc-service.ts` + +Same pattern as 2.1. The deps adapter (100 lines) maps main.ts state for IPC +handlers. Merge the defensive null checks and window guards into the IPC handlers +that need them. + +- Delete: `ipc-deps-runtime-service.ts`, `ipc-deps-runtime-service.test.ts` +- Modify: `ipc-service.ts` + +### 2.3 Merge `tokenizer-deps-runtime-service.ts` into `tokenizer-service.ts` + +The adapter (45 lines) has one non-trivial function (`tokenizeWithMecab` with null +checks and token merging). Move that logic into `tokenizer-service.ts`. + +- Delete: `tokenizer-deps-runtime-service.ts`, `tokenizer-deps-runtime-service.test.ts` +- Modify: `tokenizer-service.ts` + +### 2.4 Merge `app-lifecycle-deps-runtime-service.ts` into `app-lifecycle-service.ts` + +The adapter (57 lines) wraps Electron app events. Merge event binding into the +lifecycle service itself since it already knows about Electron's app lifecycle. + +- Delete: `app-lifecycle-deps-runtime-service.ts`, `app-lifecycle-deps-runtime-service.test.ts` +- Modify: `app-lifecycle-service.ts` + +### Phase 2 verification + +```bash +pnpm run build && pnpm run test:core +``` + +**Expected result**: 8 more files deleted. DI adapters absorbed into the services +they feed. `index.ts` shrinks further. + +--- + +## Phase 3: Consolidate Related Services + +Merge services that are split across multiple files but represent a single concern. + +### 3.1 Merge overlay visibility files + +`overlay-visibility-runtime-service.ts` (46 lines) is a thin orchestration layer +over `overlay-visibility-service.ts` (183 lines). Merge into one file: +`overlay-visibility-service.ts`. + +- Delete: `overlay-visibility-runtime-service.ts` +- Modify: `overlay-visibility-service.ts` — absorb the 3 exported functions + +### 3.2 Merge overlay broadcast files + +`overlay-broadcast-runtime-service.ts` (45 lines) contains utility functions for +window filtering and broadcasting. These are closely related to +`overlay-manager-service.ts` (49 lines) which manages the window references. +Merge broadcast functions into the overlay manager since it already owns the +window state. + +- Delete: `overlay-broadcast-runtime-service.ts`, `overlay-broadcast-runtime-service.test.ts` +- Modify: `overlay-manager-service.ts` — add broadcast methods + +### 3.3 Merge overlay shortcut files + +There are 4 shortcut-related files: + +- `overlay-shortcut-service.ts` (169 lines) — registration +- `overlay-shortcut-runtime-service.ts` (105 lines) — runtime handlers +- `overlay-shortcut-lifecycle-service.ts` (52 lines) — sync/refresh/unregister +- `overlay-shortcut-fallback-runner.ts` (114 lines) — local fallback execution + +Consolidate into 2 files: + +- `overlay-shortcut-service.ts` — registration + lifecycle (absorb lifecycle-service) +- `overlay-shortcut-handler.ts` — runtime handlers + fallback runner + +- Delete: `overlay-shortcut-lifecycle-service.ts`, `overlay-shortcut-fallback-runner.ts` + +### 3.4 Merge numeric shortcut files + +`numeric-shortcut-runtime-service.ts` (37 lines) and +`numeric-shortcut-session-service.ts` (99 lines) are two halves of one feature. +Merge into `numeric-shortcut-service.ts`. + +- Delete: `numeric-shortcut-runtime-service.ts`, `numeric-shortcut-runtime-service.test.ts` +- Modify: `numeric-shortcut-session-service.ts` → rename to `numeric-shortcut-service.ts` + +### 3.5 Merge startup/bootstrap files + +`startup-bootstrap-runtime-service.ts` (53 lines) and +`app-ready-runtime-service.ts` (77 lines) are both startup orchestration. +Merge into a single `startup-service.ts`. + +- Delete: `startup-bootstrap-runtime-service.ts`, `startup-bootstrap-runtime-service.test.ts` +- Modify: `app-ready-runtime-service.ts` → rename to `startup-service.ts`, absorb bootstrap + +### Phase 3 verification + +```bash +pnpm run build && pnpm run test:core +``` + +**Expected result**: ~10 more files deleted. Related services consolidated into +single cohesive modules. + +--- + +## Phase 4: Fix Bugs and Code Quality + +### 4.1 Remove debug `console.log` statements + +`overlay-visibility-service.ts` has 7+ raw `console.log`/`console.warn` calls +used for debugging. Remove them or replace with the app logger if the messages +have ongoing diagnostic value. + +### 4.2 Fix `as never` type cast + +`tokenizer-deps-runtime-service.ts` (or its successor after Phase 2) uses +`return mergeTokens(rawTokens as never)`. Investigate the actual type mismatch +and fix it properly. + +### 4.3 Guard `fieldGroupingResolver` against race conditions + +In main.ts, the `fieldGroupingResolver` is a single global variable. If two +field grouping requests arrive concurrently, the second overwrites the first's +resolver. Add a request ID or sequence number so stale resolutions are ignored. + +### 4.4 Audit async callbacks in CLI command handlers + +Verify that async functions passed as callbacks in the CLI command and IPC handler +wiring (main.ts lines ~697-707, ~1347, ~1360) are properly awaited or have +`.catch()` handlers so rejections aren't silently swallowed. + +### 4.5 Drop the `-runtime-service` naming convention + +After phases 1-3, rename remaining files to just `*-service.ts`. The "runtime" +prefix adds no meaning. Do this as a batch rename commit with no logic changes. + +### Phase 4 verification + +```bash +pnpm run build && pnpm run test:core +``` + +Manually smoke test: launch SubMiner, verify overlay renders, mine a card, toggle +field grouping. + +--- + +## Phase 5: Add Tests for Critical Untested Services + +These are the highest-risk untested modules. Add focused tests that verify +real behavior, not just that mocks were called. + +### 5.1 `mpv-service.ts` (761 lines, untested) + +Test the IPC protocol layer: + +- Socket message parsing (JSON line protocol) +- Property change event dispatch +- Request/response matching via request IDs +- Reconnection behavior on socket close +- Subtitle text extraction from property changes + +### 5.2 `subsync-service.ts` (427 lines, untested) + +Test: + +- Config resolution (alass vs ffsubsync path selection) +- Command construction for each sync engine +- Timeout and error handling for child processes +- Result parsing + +### 5.3 `tokenizer-service.ts` (305 lines, untested) + +Test: + +- Yomitan parser initialization and readiness +- Token extraction from parsed results +- Fallback behavior when parser unavailable +- Edge cases: empty text, CJK-only, mixed content + +### 5.4 `cli-command-service.ts` (204 lines, partially tested) + +Expand existing tests to cover: + +- All CLI command dispatch paths +- Error propagation from async handlers +- Second-instance argument forwarding + +### Phase 5 verification + +```bash +pnpm run test:core +``` + +All new tests pass. Aim for the 4 services above to each have 5-10 meaningful +test cases. + +--- + +## Phase 6 (Optional): Domain-Based Directory Structure + +After phases 1-5, the service count should be roughly 20-25 files down from 47. +If that still feels too flat, group by domain: + +``` +src/core/ + mpv/ + mpv-service.ts + mpv-render-metrics-service.ts + overlay/ + overlay-manager-service.ts + overlay-visibility-service.ts + overlay-window-service.ts + overlay-shortcut-service.ts + overlay-shortcut-handler.ts + mining/ + mining-runtime-service.ts + field-grouping-service.ts + field-grouping-overlay-service.ts + startup/ + startup-service.ts + app-lifecycle-service.ts + ipc/ + ipc-service.ts + ipc-command-service.ts + shortcuts/ + shortcut-service.ts + numeric-shortcut-service.ts + services/ + tokenizer-service.ts + subtitle-position-service.ts + subtitle-ws-service.ts + texthooker-service.ts + yomitan-extension-loader-service.ts + yomitan-settings-service.ts + secondary-subtitle-service.ts + runtime-config-service.ts + runtime-options-runtime-service.ts + cli-command-service.ts +``` + +Only do this if the flat directory still feels unwieldy after consolidation. +This is cosmetic and low-priority relative to phases 1-5. + +--- + +## Summary + +| Phase | Files Deleted | Files Modified | Risk | Effort | +| -------------------------- | ------------------- | ----------------- | ------ | ------ | +| 1. Delete thin wrappers | 16 (9 svc + 7 test) | main.ts, index.ts | Low | Small | +| 2. Consolidate DI adapters | 8 (4 svc + 4 test) | 4 services | Medium | Medium | +| 3. Merge related services | ~10 | ~5 services | Medium | Medium | +| 4. Fix bugs & rename | 0 | ~6 files | Low | Small | +| 5. Add critical tests | 0 | 4 new test files | Low | Medium | +| 6. Directory restructure | 0 | All imports | Low | Small | + +**Net result**: ~34 files deleted, service count from 47 → ~22, index.ts from +92 exports → ~45, and the remaining services each have a clear reason to exist.