diff --git a/.github/workflows/claude.yml b/.github/workflows/claude.yml index d300267..9471a05 100644 --- a/.github/workflows/claude.yml +++ b/.github/workflows/claude.yml @@ -47,4 +47,3 @@ jobs: # See https://github.com/anthropics/claude-code-action/blob/main/docs/usage.md # or https://code.claude.com/docs/en/cli-reference for available options # claude_args: '--allowed-tools Bash(gh pr:*)' - diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..78e3fd0 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,6 @@ +node_modules +dist +release +coverage +vendor +*.log diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..5e2863a --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,5 @@ +{ + "printWidth": 100, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/Makefile b/Makefile index 4270d5e..a462a42 100644 --- a/Makefile +++ b/Makefile @@ -97,8 +97,8 @@ deps: ensure-bun: @command -v bun >/dev/null 2>&1 || { printf '%s\n' "[ERROR] bun not found"; exit 1; } -pretty: - @bunx prettier --write 'src/**/*.ts' +pretty: ensure-bun + @bun run format build: @printf '%s\n' "[INFO] Detected platform: $(PLATFORM)" diff --git a/backlog/archive/milestones/m-0 - codebase-clarity-&-composability.md b/backlog/archive/milestones/m-0 - codebase-clarity-&-composability.md index bfb2d13..fb4c0f0 100644 --- a/backlog/archive/milestones/m-0 - codebase-clarity-&-composability.md +++ b/backlog/archive/milestones/m-0 - codebase-clarity-&-composability.md @@ -1,6 +1,6 @@ --- id: m-0 -title: "Codebase Clarity & Composability" +title: 'Codebase Clarity & Composability' --- ## Description diff --git a/backlog/archive/tasks/task-19 - Enable-overlay-keybinds-whenever-app-runtime-is-active.md b/backlog/archive/tasks/task-19 - Enable-overlay-keybinds-whenever-app-runtime-is-active.md index 783ef19..85ab0d4 100644 --- a/backlog/archive/tasks/task-19 - Enable-overlay-keybinds-whenever-app-runtime-is-active.md +++ b/backlog/archive/tasks/task-19 - Enable-overlay-keybinds-whenever-app-runtime-is-active.md @@ -13,12 +13,15 @@ priority: high ## Description + Restored task after accidental cleanup. Ensure keybindings are available whenever the Electron runtime is active, while respecting focused overlay/input contexts that require local key handling. + ## Implementation Notes + Started implementation: tracing overlay shortcut registration lifecycle and runtime activation gating. Root cause: overlay shortcut sync executes during overlay runtime initialization before overlayRuntimeInitialized is set true, so registration could be skipped until a later visibility toggle. @@ -32,12 +35,15 @@ Updated CLI runtime gating so --start initializes overlay runtime, which activat User clarified MPV-only workflow requirement. Added MPV plugin keybindings and script messages for mining/runtime actions (copy/mine/multi/mode/field-grouping/subsync/audio-card/runtime-options) so these actions are available from mpv chord bindings without relying on overlay global shortcuts. Per user direction, reverted all shortcut/runtime/plugin changes from this implementation cycle. Desired behavior is to keep keybindings working only when overlay is active. + ## Final Summary + Ensured overlay shortcuts are available as soon as overlay runtime becomes active by resyncing after activation flag is set. This prevents startup states where shortcuts remained inactive until a later overlay visibility change. Follow-up fix: included --start in overlay-runtime-required commands so keybinds are active right after startup, even before toggling visible/invisible overlays. + diff --git a/backlog/archive/tasks/task-20 - Implement-content-bounded-overlay-windows-and-decoupled-secondary-top-bar.md b/backlog/archive/tasks/task-20 - Implement-content-bounded-overlay-windows-and-decoupled-secondary-top-bar.md index 4b4182e..c22e74e 100644 --- a/backlog/archive/tasks/task-20 - Implement-content-bounded-overlay-windows-and-decoupled-secondary-top-bar.md +++ b/backlog/archive/tasks/task-20 - Implement-content-bounded-overlay-windows-and-decoupled-secondary-top-bar.md @@ -13,11 +13,15 @@ priority: high ## Description + Implement the overlay sizing redesign documented in `overlay_window.md`: move visible/invisible overlays from fullscreen bounds to content-bounded sizing, and decouple secondary subtitle rendering into an independent top bar window/lifecycle. + ## Acceptance Criteria + + - [ ] #1 Per-layer bounds ownership is implemented for overlay windows (no shared full-bounds setter for all layers). - [ ] #2 Renderer-to-main IPC contract exists for measured overlay content bounds with layer identity and safe validation. - [ ] #3 Visible and invisible overlays use content-bounded sizing with padding/clamp/jitter protections and full-bounds fallback when measurements are unavailable. diff --git a/backlog/archive/tasks/task-20.3 - Implement-content-bounded-sizing-algorithm-for-visible-and-invisible-overlay-windows.md b/backlog/archive/tasks/task-20.3 - Implement-content-bounded-sizing-algorithm-for-visible-and-invisible-overlay-windows.md index 2576f0d..e3865e7 100644 --- a/backlog/archive/tasks/task-20.3 - Implement-content-bounded-sizing-algorithm-for-visible-and-invisible-overlay-windows.md +++ b/backlog/archive/tasks/task-20.3 - Implement-content-bounded-sizing-algorithm-for-visible-and-invisible-overlay-windows.md @@ -16,11 +16,15 @@ priority: medium ## Description + Implement content-bounded sizing for visible/invisible windows using measured rects plus tracker origin, with robust clamping and jitter resistance. + ## Acceptance Criteria + + - [ ] #1 Bounds algorithm applies configurable padding, minimum size, display-workarea clamp, and integer snap. - [ ] #2 Main-process bounds updates are thresholded/debounced to reduce jitter and unnecessary `setBounds` churn. - [ ] #3 When no valid measurement exists, layer falls back to safe tracker/display bounds without breaking interaction. diff --git a/backlog/archive/tasks/task-20.4 - Implement-dedicated-secondary-top-bar-overlay-window.md b/backlog/archive/tasks/task-20.4 - Implement-dedicated-secondary-top-bar-overlay-window.md index 8080fe2..1afa555 100644 --- a/backlog/archive/tasks/task-20.4 - Implement-dedicated-secondary-top-bar-overlay-window.md +++ b/backlog/archive/tasks/task-20.4 - Implement-dedicated-secondary-top-bar-overlay-window.md @@ -13,11 +13,15 @@ priority: medium ## Description + Create and integrate a dedicated secondary subtitle overlay window with independent lifecycle, z-order, bounds, and pointer policy, decoupled from primary visible/invisible overlay windows. + ## Acceptance Criteria + + - [ ] #1 A third overlay window dedicated to secondary subtitles is created and managed alongside existing visible/invisible windows. - [ ] #2 Secondary window visibility follows secondary mode semantics (`hidden`/`visible`/`hover`) independent of primary overlay visibility. - [ ] #3 Secondary subtitle text/mode/style updates are routed directly to the secondary window renderer path. diff --git a/backlog/archive/tasks/task-20.5 - Add-rollout-guards-tests-and-validation-matrix-for-content-bounded-overlays.md b/backlog/archive/tasks/task-20.5 - Add-rollout-guards-tests-and-validation-matrix-for-content-bounded-overlays.md index 347ac99..43dd4fa 100644 --- a/backlog/archive/tasks/task-20.5 - Add-rollout-guards-tests-and-validation-matrix-for-content-bounded-overlays.md +++ b/backlog/archive/tasks/task-20.5 - Add-rollout-guards-tests-and-validation-matrix-for-content-bounded-overlays.md @@ -13,11 +13,15 @@ priority: medium ## Description + Add safety controls and verification coverage for the new content-bounded overlay architecture and secondary top-bar window. + ## Acceptance Criteria + + - [ ] #1 Feature flag or equivalent rollout guard exists for switching to new sizing/window behavior. - [ ] #2 Service-level/unit tests cover bounds clamping, jitter thresholding, invalid measurement fallback, and per-layer updates. - [ ] #3 Manual validation checklist documents and verifies wrap/no-wrap, style changes, monitor moves, tracker churn, modal interactions, and simultaneous overlay states. diff --git a/backlog/archive/tasks/task-22 - Make-secondary-subtitles-hover-revealed-but-non-lookupable-in-Yomitan-sessions.md b/backlog/archive/tasks/task-22 - Make-secondary-subtitles-hover-revealed-but-non-lookupable-in-Yomitan-sessions.md index ccfa18b..f141d64 100644 --- a/backlog/archive/tasks/task-22 - Make-secondary-subtitles-hover-revealed-but-non-lookupable-in-Yomitan-sessions.md +++ b/backlog/archive/tasks/task-22 - Make-secondary-subtitles-hover-revealed-but-non-lookupable-in-Yomitan-sessions.md @@ -12,11 +12,15 @@ priority: high ## Description + Investigate and implement a UX where secondary subtitles (e.g., English text in our current sessions) become visible when hovered, while explicitly preventing user interactions that allow text lookup (including Yomitan integration) on those subtitles. This should allow readability-on-hover without exposing the secondary overlay text to selection/lookup workflows. + ## Acceptance Criteria + + - [ ] #1 Secondary subtitles become visible only while hovered (or via equivalent hover-triggered mechanism), and return to default hidden/low-visibility state when not hovered. - [ ] #2 When hovered, secondary subtitles do not trigger Yomitan lookup behavior in sessions where Yomitan is enabled. - [ ] #3 Secondary subtitles remain non-interactive for lookup paths (for example, text selection or lookup event propagation) while hover-visibility still works as intended. @@ -25,6 +29,8 @@ Investigate and implement a UX where secondary subtitles (e.g., English text in ## Definition of Done + + - [ ] #1 Acceptance criteria are reviewed and covered by explicit manual/automated test coverage for hover reveal and lookup suppression behavior. diff --git a/backlog/archive/tasks/task-30 - Enable-anime-streaming-via-extension-repos-with-configurable-mpv-playback-flow.md b/backlog/archive/tasks/task-30 - Enable-anime-streaming-via-extension-repos-with-configurable-mpv-playback-flow.md index 03e8a00..c33d1e4 100644 --- a/backlog/archive/tasks/task-30 - Enable-anime-streaming-via-extension-repos-with-configurable-mpv-playback-flow.md +++ b/backlog/archive/tasks/task-30 - Enable-anime-streaming-via-extension-repos-with-configurable-mpv-playback-flow.md @@ -13,13 +13,17 @@ priority: high ## Description + Add a feature to query configured extension repositories for anime titles/episodes from SubMiner, let users select a streamable source, and play it through mpv with minimal friction. The result should be interactive from Electron (and triggered from mpv via existing command bridge), and fully configurable in app config. The implementation should provide a modular backend resolver and a clear UI flow that mirrors existing modal interaction patterns, while keeping mpv playback unchanged (use loadfile with resolved URL and optional headers/referrer metadata). + ## Acceptance Criteria + + - [ ] #1 Create a stable config schema for one or more extension source backends (repos/endpoints/flags) and persist in user config + default template. - [ ] #2 Resolve an anime search term to candidate series from configured sources. - [ ] #3 Resolve an episode selection to at least one playable stream URL candidate with playback metadata when available. @@ -32,13 +36,17 @@ The implementation should provide a modular backend resolver and a clear UI flow ## Implementation Notes + Execution sequence for implementation: 1) TASK-30.1 (config/model), 2) TASK-30.2 (resolver), 3) TASK-30.3 (IPC), 4) TASK-30.4 (UI modal), 5) TASK-30.5 (mpv trigger), 6) TASK-30.6 (validation/rollout checklist). Rollout recommendation: complete TASK-30.6 only after TASK-30.1-30.5 are done and can be verified in combination. + ## Definition of Done + + - [ ] #1 Config schema validated in app startup (bad config surfaces clear error). - [ ] #2 No hardcoded source/resolver URLs in UI layer; resolver details are backend-driven. - [ ] #3 Play command path uses existing mpv IPC/runtime helpers. diff --git a/backlog/archive/tasks/task-30.1 - Design-extension-source-config-model-and-defaults.md b/backlog/archive/tasks/task-30.1 - Design-extension-source-config-model-and-defaults.md index c91e6e1..3e9af80 100644 --- a/backlog/archive/tasks/task-30.1 - Design-extension-source-config-model-and-defaults.md +++ b/backlog/archive/tasks/task-30.1 - Design-extension-source-config-model-and-defaults.md @@ -14,11 +14,15 @@ priority: high ## Description + Define a backend-agnostic configuration contract for extension repository streaming, including resolver endpoints/process mode, query/auth headers, timeouts, enable flags, and source preference. Wire schema through Config/ResolvedConfig and generated template/defaults so users can manage repos entirely through config. + ## Acceptance Criteria + + - [ ] #1 Add new config sections for extension source providers in Config and ResolvedConfig types. - [ ] #2 Add validation defaults and env-compatible parsing for provider list, auth, header overrides, and feature flags. - [ ] #3 Update config template and docs text so defaults are discoverable and editable. @@ -29,11 +33,15 @@ Define a backend-agnostic configuration contract for extension repository stream ## Implementation Notes + Phase 1 — Foundation: config contract + validation + defaults + ## Definition of Done + + - [ ] #1 Config examples in template/docs include at least one provider entry shape. - [ ] #2 Defaults remain backward-compatible when key is absent. - [ ] #3 Feature can be disabled without touching unrelated settings. diff --git a/backlog/archive/tasks/task-30.2 - Implement-extension-resolver-service-search-episode-stream-resolution.md b/backlog/archive/tasks/task-30.2 - Implement-extension-resolver-service-search-episode-stream-resolution.md index d75500e..45ff13d 100644 --- a/backlog/archive/tasks/task-30.2 - Implement-extension-resolver-service-search-episode-stream-resolution.md +++ b/backlog/archive/tasks/task-30.2 - Implement-extension-resolver-service-search-episode-stream-resolution.md @@ -15,11 +15,15 @@ priority: high ## Description + Build a dedicated service in main process that queries configured extension repos and normalizes results into a unified internal model, including optional playback metadata. Keep transport abstracted so future backends (local process, remote API, Manatán-compatible source) can be swapped without changing renderer contracts. + ## Acceptance Criteria + + - [ ] #1 Create a typed internal model for source, series, episode, and playable candidate with fields for quality/audio/headers/referrer/userAgent. - [ ] #2 Implement provider abstraction with pluggable fetch/execution strategy from config. - [ ] #3 Add services for searchAnime, listEpisodes, resolveStream (or equivalent) with cancellation/error boundaries. @@ -30,11 +34,15 @@ Build a dedicated service in main process that queries configured extension repo ## Implementation Notes + Phase 2 — Core service: provider integration and stream resolution + ## Definition of Done + + - [ ] #1 Resolver never leaks raw provider payload to renderer. - [ ] #2 Streaming URL output includes reason for failure when unavailable. - [ ] #3 Service boundaries allow unit-level validation of request/response mapping logic. diff --git a/backlog/archive/tasks/task-30.3 - Expose-resolver-operations-via-Electron-IPC-to-renderer.md b/backlog/archive/tasks/task-30.3 - Expose-resolver-operations-via-Electron-IPC-to-renderer.md index 96330ed..3e03ad0 100644 --- a/backlog/archive/tasks/task-30.3 - Expose-resolver-operations-via-Electron-IPC-to-renderer.md +++ b/backlog/archive/tasks/task-30.3 - Expose-resolver-operations-via-Electron-IPC-to-renderer.md @@ -15,11 +15,15 @@ priority: high ## Description + Add a typed preload and main-IPC contract for streaming queries and playback resolution so the renderer can initiate search/list/resolve without embedding network/provider logic in UI code. + ## Acceptance Criteria + + - [ ] #1 Define IPC handlers in main with input/output schema validation and timeouts. - [ ] #2 Expose corresponding functions in preload `window.electronAPI` and ElectronAPI types. - [ ] #3 Reuse existing mpv command channel for playback and add a dedicated request/response flow for resolver actions. @@ -31,11 +35,15 @@ Add a typed preload and main-IPC contract for streaming queries and playback res ## Implementation Notes + Phase 3 — API surface: IPC/preload contract for resolver operations + ## Definition of Done + + - [ ] #1 Renderer code can query providers without importing Node-only modules. - [ ] #2 IPC paths have clear names and consistent response shapes across all calls. - [ ] #3 Error paths return explicit machine-readable codes mapped to user-visible messages. diff --git a/backlog/archive/tasks/task-30.4 - Add-interactive-streaming-modal-search-episode-list-source-selection-play.md b/backlog/archive/tasks/task-30.4 - Add-interactive-streaming-modal-search-episode-list-source-selection-play.md index a2be6c2..af9eb28 100644 --- a/backlog/archive/tasks/task-30.4 - Add-interactive-streaming-modal-search-episode-list-source-selection-play.md +++ b/backlog/archive/tasks/task-30.4 - Add-interactive-streaming-modal-search-episode-list-source-selection-play.md @@ -15,11 +15,15 @@ priority: high ## Description + Implement a renderer flow to query configured providers, display results, let user choose series and episode, and trigger playback for a selected stream. The UI should support keyboard interactions and surface backend errors clearly. + ## Acceptance Criteria + + - [ ] #1 Create modal UI/state model for query, results list, selected item, episode list, candidate qualities, and loading/error status. - [ ] #2 Wire renderer actions to new IPC methods for search/episode/resolve. - [ ] #3 Render one-click or enter-to-play action that calls existing mpv playback pathway. @@ -31,11 +35,15 @@ Implement a renderer flow to query configured providers, display results, let us ## Implementation Notes + Phase 4 — UX: interactive modal flow and playback callout + ## Definition of Done + + - [ ] #1 Modal state is isolated and unsubscribes listeners on close. - [ ] #2 No direct network logic in renderer beyond IPC calls. - [ ] #3 Visual style and behavior are consistent with existing modal patterns. diff --git a/backlog/archive/tasks/task-30.5 - Wire-mpv-script-message-shortcut-trigger-into-streaming-modal-and-playback-path.md b/backlog/archive/tasks/task-30.5 - Wire-mpv-script-message-shortcut-trigger-into-streaming-modal-and-playback-path.md index b19ed4f..836158e 100644 --- a/backlog/archive/tasks/task-30.5 - Wire-mpv-script-message-shortcut-trigger-into-streaming-modal-and-playback-path.md +++ b/backlog/archive/tasks/task-30.5 - Wire-mpv-script-message-shortcut-trigger-into-streaming-modal-and-playback-path.md @@ -18,11 +18,15 @@ priority: high ## Description + Allow users to open streaming selection from within mpv via keybind/menu and route that intent into renderer modal and playback flow without requiring separate window focus changes. + ## Acceptance Criteria + + - [ ] #1 Add/extend mpv Lua plugin or existing command registry to emit a custom action for opening the streaming picker. - [ ] #2 Handle this action in main IPC/mpv-command pipeline and forward to renderer modal state. - [ ] #3 Add at least one default keybinding/menu entry documented in config/plugin notes. @@ -33,11 +37,15 @@ Allow users to open streaming selection from within mpv via keybind/menu and rou ## Implementation Notes + Phase 5 — In-player entry: mpv trigger/menu integration + ## Definition of Done + + - [ ] #1 No duplicate mpv command parsing between picker and legacy commands. - [ ] #2 Feature can be used in overlay and mpv-only mode where applicable. - [ ] #3 No dependency on modal open state when launched by mpv trigger. diff --git a/backlog/archive/tasks/task-30.6 - Add-integration-validation-plan-and-rollout-checklist-for-anime-streaming-feature.md b/backlog/archive/tasks/task-30.6 - Add-integration-validation-plan-and-rollout-checklist-for-anime-streaming-feature.md index 7120183..6887aa2 100644 --- a/backlog/archive/tasks/task-30.6 - Add-integration-validation-plan-and-rollout-checklist-for-anime-streaming-feature.md +++ b/backlog/archive/tasks/task-30.6 - Add-integration-validation-plan-and-rollout-checklist-for-anime-streaming-feature.md @@ -16,11 +16,15 @@ priority: high ## Description + Create a concrete validation task that defines end-to-end acceptance checks for config loading, resolver behavior, IPC contract correctness, UI flow, and mpv-triggered launch. The checklist should be actionable and align with existing project conventions so completion can be verified without guesswork. + ## Acceptance Criteria + + - [ ] #1 Define test scenarios for config success/failure cases, including invalid provider config and feature disabled mode. - [ ] #2 Define search/list/resolve API contract tests and error-code assertions (empty, timeout, auth error, no playable URL). - [ ] #3 Define renderer UX checks for modal state transitions, loading indicators, empty results, selection, and play invocation. @@ -33,11 +37,15 @@ Create a concrete validation task that defines end-to-end acceptance checks for ## Implementation Notes + Phase 6 — Validation: rollout, smoke tests, and release readiness checklist + ## Definition of Done + + - [ ] #1 Checklist covers happy-path and failure-path for each task dependency. - [ ] #2 Verification steps are executable without external tooling assumptions. - [ ] #3 No task can be marked done without explicit evidence fields filled in. diff --git a/backlog/archive/tasks/task-30.7 - Add-English-source-preference-hard-sub-stripping-workflow-in-Aniyomi-streaming-path.md b/backlog/archive/tasks/task-30.7 - Add-English-source-preference-hard-sub-stripping-workflow-in-Aniyomi-streaming-path.md index 52f67f4..963487c 100644 --- a/backlog/archive/tasks/task-30.7 - Add-English-source-preference-hard-sub-stripping-workflow-in-Aniyomi-streaming-path.md +++ b/backlog/archive/tasks/task-30.7 - Add-English-source-preference-hard-sub-stripping-workflow-in-Aniyomi-streaming-path.md @@ -17,11 +17,15 @@ priority: high ## Description + Improve the Aniyomi/anime extension streaming flow to prefer English-capable sources with soft subtitles, and automatically recover when only hard-subbed streams are available by stripping embedded subtitles with ffmpeg and attaching external Jimaku subtitle files into mpv. + ## Acceptance Criteria + + - [ ] #1 During source scoring/selection, prefer providers/sources that declare or expose soft subtitles for English audio or subtitle tracks over hard-subbed alternatives. - [ ] #2 Add a config option for preferred language targets (default English) and fallback policy (favor soft subtitles, then hard-sub fallback). - [ ] #3 Detect when a resolved stream is hard-sub-only and a soft-sub source is unavailable for the same episode. diff --git a/backlog/archive/tasks/task-30.8 - Add-observability-and-tuning-metrics-for-Aniyomi-subtitle-source-fallback-decisions.md b/backlog/archive/tasks/task-30.8 - Add-observability-and-tuning-metrics-for-Aniyomi-subtitle-source-fallback-decisions.md index 6031412..654bd35 100644 --- a/backlog/archive/tasks/task-30.8 - Add-observability-and-tuning-metrics-for-Aniyomi-subtitle-source-fallback-decisions.md +++ b/backlog/archive/tasks/task-30.8 - Add-observability-and-tuning-metrics-for-Aniyomi-subtitle-source-fallback-decisions.md @@ -16,11 +16,15 @@ priority: high ## Description + Add lightweight telemetry/analytics hooks (local logs + optional structured counters) to measure how Aniyomi/anime streaming source selection behaves, including soft-sub preference, hard-sub fallback usage, and ffmpeg+Jimaku post-processing outcomes, to support source ranking tuning. + ## Acceptance Criteria + + - [ ] #1 Track per-playback decision metadata including chosen source, language match score, subtitle mode (soft/hard), and reason for source preference ordering. - [ ] #2 Emit success/failure counters for hard-sub stripping attempts (started/succeeded/failed/unsupported codec) with reason codes. - [ ] #3 Log whether Jimaku subtitle attachment was available and successfully loaded for ffmpeg-assisted flows. diff --git a/backlog/archive/tasks/task-30.9 - Expose-subtitle-preference-and-ffmpeg-fallback-tuning-controls-in-settings-UI.md b/backlog/archive/tasks/task-30.9 - Expose-subtitle-preference-and-ffmpeg-fallback-tuning-controls-in-settings-UI.md index 1d0fd36..872c715 100644 --- a/backlog/archive/tasks/task-30.9 - Expose-subtitle-preference-and-ffmpeg-fallback-tuning-controls-in-settings-UI.md +++ b/backlog/archive/tasks/task-30.9 - Expose-subtitle-preference-and-ffmpeg-fallback-tuning-controls-in-settings-UI.md @@ -15,11 +15,15 @@ priority: medium ## Description + Add user-configurable controls for Aniyomi streaming subtitle behavior, including preferred language profile, soft-vs-hard source preference, ffmpeg-assisted hard-sub removal behavior, and policy toggles so quality and fallback behavior can be tuned without code changes. + ## Acceptance Criteria + + - [ ] #1 Add settings UI fields to define preferred subtitle/audiotrack language order (e.g., en, ja) and enable/disable hard-sub fallback mode. - [ ] #2 Add explicit toggle for enabling hard-sub stripping via ffmpeg and configurable timeout/quality limits to avoid long waits. - [ ] #3 Expose source ranking preferences for soft-sub vs hard-sub sources and optional fallback to native/transcoded source when preferred modes are unavailable. diff --git a/backlog/archive/tasks/task-43 - Add-community-subtitle-timing-database-for-shared-sync-corrections.md b/backlog/archive/tasks/task-43 - Add-community-subtitle-timing-database-for-shared-sync-corrections.md index 65f5a39..7924bbc 100644 --- a/backlog/archive/tasks/task-43 - Add-community-subtitle-timing-database-for-shared-sync-corrections.md +++ b/backlog/archive/tasks/task-43 - Add-community-subtitle-timing-database-for-shared-sync-corrections.md @@ -16,12 +16,15 @@ priority: low ## Description + Allow users to share their subtitle timing corrections to a community database, so other users watching the same video file get pre-synced subtitles automatically. ## Motivation + Subtitle synchronization (alass/ffsubsync) is one of the most friction-heavy steps in the mining workflow. Users spend time syncing subtitles that someone else has already synced for the exact same video. A shared database of timing corrections keyed by video file hash would eliminate redundant work. ## Design + 1. **Video identification**: Use a partial file hash (first + last N bytes, or a media fingerprint) to identify video files without uploading content 2. **Timing data**: Store the timing offset/warp parameters produced by alass/ffsubsync, not the full subtitle file 3. **Upload flow**: After a successful sync, offer to share the timing correction (opt-in) @@ -29,6 +32,7 @@ Subtitle synchronization (alass/ffsubsync) is one of the most friction-heavy ste 5. **Trust model**: Simple upvote/downvote on corrections; show number of users who confirmed a correction works ## Technical considerations + - Backend could be a simple REST API with a lightweight database (or even a GitHub-hosted JSON/SQLite file for v1) - Privacy: only file hashes and timing parameters are shared, never video content or personal data - Subtitle source (jimaku entry ID) can serve as an additional matching key @@ -36,12 +40,15 @@ Subtitle synchronization (alass/ffsubsync) is one of the most friction-heavy ste - Could integrate with existing jimaku modal flow ## Phasing + - v1: Local export/import of timing corrections (share as files) - v2: Optional cloud sync with community database ## Acceptance Criteria + + - [ ] #1 Video files are identified by content hash without uploading video data. - [ ] #2 Timing corrections (offset/warp parameters) can be exported and shared. - [ ] #3 Before syncing, the app checks for existing community corrections for the current video. diff --git a/backlog/archive/tasks/task-48 - Add-streaming-mode-integration-in-subminer-using-ani-cli-stream-source.md b/backlog/archive/tasks/task-48 - Add-streaming-mode-integration-in-subminer-using-ani-cli-stream-source.md index e2a6240..9d0aa59 100644 --- a/backlog/archive/tasks/task-48 - Add-streaming-mode-integration-in-subminer-using-ani-cli-stream-source.md +++ b/backlog/archive/tasks/task-48 - Add-streaming-mode-integration-in-subminer-using-ani-cli-stream-source.md @@ -16,11 +16,15 @@ priority: high ## Description + Implement a new streaming mode so SubMiner can resolve and play episodes via ani-cli stream sources instead of existing file/download flow. The mode is enabled with a CLI flag (`-s` / `--stream`) and, when active, should prefer streamed playback and subtitle handling that keeps Japanese (or configured primary) subtitles as the main track. If a stream lacks Japanese subtitle tracks, fetch and inject subtitles from Jimaku and set them as primary subtitles according to SubMiner config. + ## Acceptance Criteria + + - [ ] #1 Add a command-line option `-s`/`--stream` that enables streaming mode and is documented in help/config UX. - [ ] #2 When streaming mode is enabled, resolve episode/video URLs using existing ani-cli stream selection logic (ported into SubMiner) and route playback to the resolved stream source. - [ ] #3 If stream metadata contains a Japanese subtitle track, preserve that track as the primary subtitle stream path per current primary-subtitle selection behavior. @@ -32,11 +36,15 @@ Implement a new streaming mode so SubMiner can resolve and play episodes via ani ## Implementation Notes + Superseded by TASK-51. Streaming via ani-cli in subminer was removed due Cloudflare 403/unreliable source metadata; re-evaluate later if reintroduced behind a feature flag and redesigned resolver/metadata pipeline. + ## Definition of Done + + - [ ] #1 CLI accepts both `-s` and `--stream` and enables streaming-specific behavior. - [ ] #2 Streaming mode resolves streams through migrated ani-cli logic. - [ ] #3 Japanese subs are preferred from stream metadata when available; Jimaku fallback is used only when absent. diff --git a/backlog/archive/tasks/task-48.1 - Add-streaming-CLI-flag-plumbing-and-option-wiring.md b/backlog/archive/tasks/task-48.1 - Add-streaming-CLI-flag-plumbing-and-option-wiring.md index fd10c35..a16e4ee 100644 --- a/backlog/archive/tasks/task-48.1 - Add-streaming-CLI-flag-plumbing-and-option-wiring.md +++ b/backlog/archive/tasks/task-48.1 - Add-streaming-CLI-flag-plumbing-and-option-wiring.md @@ -16,11 +16,15 @@ priority: medium ## Description + Add the `-s`/`--stream` option end-to-end in SubMiner CLI and configuration handling, including defaults, help text, parsing/validation, and explicit routing so streaming mode is only enabled when requested. + ## Acceptance Criteria + + - [ ] #1 Introduce `-s` short option and `--stream` long option in CLI parsing without breaking existing flags. - [ ] #2 When set, the resulting config state reflects streaming mode enabled and is propagated to playback/session startup. - [ ] #3 When unset, behavior remains identical to current non-streaming flows. @@ -29,5 +33,7 @@ Add the `-s`/`--stream` option end-to-end in SubMiner CLI and configuration hand ## Implementation Notes + Superseded by TASK-51. CLI stream mode work deferred until streaming architecture is revisited. + diff --git a/backlog/archive/tasks/task-48.2 - Port-ani-cli-stream-resolution-logic-into-SubMiner.md b/backlog/archive/tasks/task-48.2 - Port-ani-cli-stream-resolution-logic-into-SubMiner.md index 02fd272..b62b5b3 100644 --- a/backlog/archive/tasks/task-48.2 - Port-ani-cli-stream-resolution-logic-into-SubMiner.md +++ b/backlog/archive/tasks/task-48.2 - Port-ani-cli-stream-resolution-logic-into-SubMiner.md @@ -16,11 +16,15 @@ priority: high ## Description + Implement stream URL resolution by porting ani-cli logic for selecting providers/episodes and obtaining playable stream URLs so SubMiner can consume stream sources directly. + ## Acceptance Criteria + + - [ ] #1 Encapsulate stream search/provider selection logic in a dedicated module in SubMiner. - [ ] #2 Resolve episode query input into a canonical playable stream URL in streaming mode. - [ ] #3 Preserve existing behavior for non-streaming flow and expose errors when stream resolution fails. @@ -29,5 +33,7 @@ Implement stream URL resolution by porting ani-cli logic for selecting providers ## Implementation Notes + Superseded by TASK-51. Stream URL resolution via ani-cli postponed; previous attempt exposed anti-bot/403 fragility and poor title-source reliability. + diff --git a/backlog/archive/tasks/task-48.3 - Implement-stream-subtitle-selection-and-primary-language-precedence.md b/backlog/archive/tasks/task-48.3 - Implement-stream-subtitle-selection-and-primary-language-precedence.md index b9e2708..fe02761 100644 --- a/backlog/archive/tasks/task-48.3 - Implement-stream-subtitle-selection-and-primary-language-precedence.md +++ b/backlog/archive/tasks/task-48.3 - Implement-stream-subtitle-selection-and-primary-language-precedence.md @@ -16,11 +16,15 @@ priority: high ## Description + Handle subtitle track selection for stream playback so Japanese (or configured primary language) subtitle behavior is correctly applied when stream metadata includes or omits JP tracks. + ## Acceptance Criteria + + - [ ] #1 Use stream metadata to choose and mark the configured primary language subtitle as active when available. - [ ] #2 If no matching primary language track exists in stream metadata, keep previous fallback behavior only for non-streaming mode. - [ ] #3 When no Japanese track exists and config primary is different, explicitly set configured primary as primary track for streaming flow. @@ -29,5 +33,7 @@ Handle subtitle track selection for stream playback so Japanese (or configured p ## Implementation Notes + Superseded by TASK-51. Stream subtitle language precedence in streaming mode deferred with full design revisit. + diff --git a/backlog/archive/tasks/task-48.4 - Add-Jimaku-subtitle-fallback-for-stream-mode.md b/backlog/archive/tasks/task-48.4 - Add-Jimaku-subtitle-fallback-for-stream-mode.md index 3a9be2d..8dedf13 100644 --- a/backlog/archive/tasks/task-48.4 - Add-Jimaku-subtitle-fallback-for-stream-mode.md +++ b/backlog/archive/tasks/task-48.4 - Add-Jimaku-subtitle-fallback-for-stream-mode.md @@ -17,11 +17,15 @@ priority: medium ## Description + When a resolved stream lacks JP/primary-language tracks, fetch subtitles from Jimaku and inject them for playback, overriding non-primary subtitle defaults in streaming mode according to config. + ## Acceptance Criteria + + - [ ] #1 Detect missing primary subtitle from stream metadata and trigger Jimaku lookup for matching episode. - [ ] #2 Load fetched Jimaku subtitles into playback pipeline and mark them as the primary subtitle track. - [ ] #3 Fallback is only used in streaming mode and should not alter subtitle behavior outside streaming. @@ -30,5 +34,7 @@ When a resolved stream lacks JP/primary-language tracks, fetch subtitles from Ji ## Implementation Notes + Superseded by TASK-51. Jimaku fallback for streams deferred along with entire streaming flow. + diff --git a/backlog/archive/tasks/task-48.5 - Add-verification-plan-tests-for-streaming-mode-behavior.md b/backlog/archive/tasks/task-48.5 - Add-verification-plan-tests-for-streaming-mode-behavior.md index c9f5435..2d0e96d 100644 --- a/backlog/archive/tasks/task-48.5 - Add-verification-plan-tests-for-streaming-mode-behavior.md +++ b/backlog/archive/tasks/task-48.5 - Add-verification-plan-tests-for-streaming-mode-behavior.md @@ -16,11 +16,15 @@ priority: low ## Description + Create a validation plan or tests for CLI flag behavior, stream resolution, and subtitle precedence/fallback rules so streaming mode changes are measurable and regressions are caught. + ## Acceptance Criteria + + - [ ] #1 Document/manual checklist covers `-s` and `--stream` invocation and streaming-only behavior. - [ ] #2 Include cases for (a) stream with JP subtitles, (b) no JP subtitles with Jimaku fallback, (c) primary-language not Japanese. - [ ] #3 Run or provide reproducible checks to confirm non-streaming behavior unchanged. @@ -29,5 +33,7 @@ Create a validation plan or tests for CLI flag behavior, stream resolution, and ## Implementation Notes + Superseded by TASK-51. Verification plan moved to deferred reimplementation context. + diff --git a/backlog/archive/tasks/task-48.6 - Wire-s-stream-mode-to-Ani-cli-and-Jimaku-subtitle-fallback.md b/backlog/archive/tasks/task-48.6 - Wire-s-stream-mode-to-Ani-cli-and-Jimaku-subtitle-fallback.md index 571ceca..b8f0f9a 100644 --- a/backlog/archive/tasks/task-48.6 - Wire-s-stream-mode-to-Ani-cli-and-Jimaku-subtitle-fallback.md +++ b/backlog/archive/tasks/task-48.6 - Wire-s-stream-mode-to-Ani-cli-and-Jimaku-subtitle-fallback.md @@ -22,11 +22,15 @@ priority: high ## Description + Implement SubMiner streaming mode end-to-end behind a `-s`/`--stream` flag. In stream mode, use the vendored ani-cli resolution flow to get playable stream URLs instead of local file/YouTube URL handling. If resolved streams do not expose Japanese subtitles, fetch matching subtitles from Jimaku and load them into mpv as the active primary subtitle track, overwriting the current non-primary/non-Japanese default according to subminer primary-subtitle configuration. + ## Acceptance Criteria + + - [ ] #1 When `subminer -s` is used, resolution should pass a search/query through ani-cli stream logic and play the resolved stream source. - [ ] #2 If the stream includes a Japanese subtitle track, preserve and select the configured primary subtitle language behavior without Jimaku injection. - [ ] #3 If no Japanese (or configured primary language) subtitle exists in stream metadata, fetch and inject Jimaku subtitles before playback starts. @@ -37,11 +41,15 @@ Implement SubMiner streaming mode end-to-end behind a `-s`/`--stream` flag. In s ## Implementation Notes + Superseded by TASK-51. End-to-end stream wiring to ani-cli is deferred. + ## Definition of Done + + - [ ] #1 CLI exposes both `-s` and `--stream` in help/config and validation. - [ ] #2 Implementation includes a clear fallback path when stream subtitles are absent and Jimaku search/download fails gracefully. - [ ] #3 Subtitles loading path avoids temp-file leaks; temporary media/subtitle artifacts are cleaned up on exit. diff --git a/backlog/archive/tasks/task-51 - Revisit-Ani-cli-stream-mode-integration-later.md b/backlog/archive/tasks/task-51 - Revisit-Ani-cli-stream-mode-integration-later.md index 5894647..0d2d832 100644 --- a/backlog/archive/tasks/task-51 - Revisit-Ani-cli-stream-mode-integration-later.md +++ b/backlog/archive/tasks/task-51 - Revisit-Ani-cli-stream-mode-integration-later.md @@ -15,9 +15,11 @@ dependencies: [] ## Description + Current codebase has removed ani-cli integration and stream-mode from subminer temporarily. Keep a deferred design task to reintroduce streaming mode in a future cycle. Findings from prior attempts: + - `subminer -s ` path relied on `ani-cli` resolving stream URLs, but returned stream URLs that are Cloudflare-protected (`tools.fast4speed.rsvp`) and often returned 403 from mpv/ytdl-hook (generic anti-bot/Forbidden). - Even after passing `ytdl` extractor args, stream playback via subminer still failed because URL/anti-bot handling differed from direct ani-cli execution context. - We also observed stream title resolution issues: selected titles from ani-cli menu were unreliable/random and broke downstream Jimaku matching behavior. @@ -25,6 +27,7 @@ Findings from prior attempts: - Based on these findings and instability, stream mode should be explicitly deferred rather than partially reintroduced. Proposal: + - Reintroduce behind a feature flag / future milestone only. - Re-design around a dedicated stream source resolver with robust URL acquisition and source metadata preservation (query/episode/title) before subtitle sync flows. diff --git a/backlog/completed/task-10 - Consolidate-service-naming-conventions-and-barrel-exports.md b/backlog/completed/task-10 - Consolidate-service-naming-conventions-and-barrel-exports.md index 3613a3b..c134b5d 100644 --- a/backlog/completed/task-10 - Consolidate-service-naming-conventions-and-barrel-exports.md +++ b/backlog/completed/task-10 - Consolidate-service-naming-conventions-and-barrel-exports.md @@ -19,7 +19,9 @@ priority: low ## Description + The service layer has inconsistent naming: + - Some functions end in `Service`: `handleCliCommandService`, `loadSubtitlePositionService` - Some end in `RuntimeService`: `replayCurrentSubtitleRuntimeService`, `sendMpvCommandRuntimeService` - Some are plain: `shortcutMatchesInputForLocalFallback` @@ -28,13 +30,16 @@ The service layer has inconsistent naming: The barrel export (src/core/services/index.ts) re-exports 79 symbols from 28 files through a single surface, which obscures dependency boundaries. Consumers import everything from `./core/services` and can't tell which service file they actually depend on. Establish consistent naming: -- Exported service functions: `verbNounService` (e.g., `handleCliCommand`) + +- Exported service functions: `verbNounService` (e.g., `handleCliCommand`) - Deps factory functions: `create*Deps` - Consider whether the barrel re-export is still the right pattern vs direct imports from individual files. ## Acceptance Criteria + + - [ ] #1 All service functions follow a consistent naming convention - [ ] #2 Decision documented on barrel export vs direct imports - [ ] #3 No functional changes @@ -43,11 +48,15 @@ Establish consistent naming: ## Implementation Notes + Naming convention consolidation should be addressed as part of TASK-27.2 (split main.ts) and TASK-27.3 (anki-integration split). As modules are extracted and given clear boundaries, naming will be standardized at each boundary. No need to do a standalone naming pass — it's wasted effort if the module structure is about to change. + ## Final Summary + Subsumed by TASK-27.2 and TASK-27.3. Naming conventions were standardized at module boundaries during extraction. A standalone global naming pass would be churn with no structural benefit now that modules have clear ownership boundaries. + diff --git a/backlog/completed/task-11 - Break-up-the-applyInvisibleSubtitleLayoutFromMpvMetrics-mega-function.md b/backlog/completed/task-11 - Break-up-the-applyInvisibleSubtitleLayoutFromMpvMetrics-mega-function.md index f7dc48c..c6da18a 100644 --- a/backlog/completed/task-11 - Break-up-the-applyInvisibleSubtitleLayoutFromMpvMetrics-mega-function.md +++ b/backlog/completed/task-11 - Break-up-the-applyInvisibleSubtitleLayoutFromMpvMetrics-mega-function.md @@ -20,19 +20,24 @@ priority: medium ## Description + In renderer.ts (around lines 865-1075), `applyInvisibleSubtitleLayoutFromMpvMetrics` is a 211-line function with up to 5 levels of nesting. It handles OSD scaling calculations, platform-specific font compensation (macOS vs Linux), DPR calculations, ASS alignment tag interpretation (\an tags), baseline compensation, line-height fixes, font property application, and transform origin — all interleaved. Extract into focused helpers: + - `calculateOsdScale(metrics, renderAreaHeight)` — pure scaling math - `calculateSubtitlePosition(metrics, scale, alignment)` — ASS \an tag interpretation + positioning - `applyPlatformFontCompensation(style, platform)` — macOS kerning/size adjustments - `applySubtitleStyle(element, computedStyle)` — DOM style application This can be done independently of or as part of TASK-6 (renderer split). + ## Acceptance Criteria + + - [x] #1 No single function exceeds ~50 lines in the positioning logic - [x] #2 Helper functions are pure where possible (take inputs, return outputs) - [x] #3 Platform-specific branches isolated into dedicated helpers @@ -42,13 +47,17 @@ This can be done independently of or as part of TASK-6 (renderer split). ## Implementation Notes + Helpers were split so positioning math, base layout, and typography/vertical handling are no longer in one monolith; see `src/renderer/positioning/invisible-layout.ts` and peer files. Applied as part of TASK-27.5 with helper extraction: moved mpv subtitle layout orchestration to `invisible-layout.ts` and extracted metric/base/style helpers into `invisible-layout-metrics.ts` and `invisible-layout-helpers.ts`. + ## Final Summary + Decomposition of `applyInvisibleSubtitleLayoutFromMpvMetrics` completed as part of TASK-27.5: function body split into metric/layout/typography helpers and small coordinator preserved. Manual validation completed by user; behavior remains stable. + diff --git a/backlog/completed/task-12 - Add-renderer-module-bundling-for-multi-file-renderer-support.md b/backlog/completed/task-12 - Add-renderer-module-bundling-for-multi-file-renderer-support.md index f2c093e..04e5874 100644 --- a/backlog/completed/task-12 - Add-renderer-module-bundling-for-multi-file-renderer-support.md +++ b/backlog/completed/task-12 - Add-renderer-module-bundling-for-multi-file-renderer-support.md @@ -23,18 +23,23 @@ priority: high ## Description + Currently renderer.ts is a single file loaded directly by Electron's renderer process via a script tag in index.html. To split it into modules (TASK-6), we need a bundling step since Electron renderer's default context doesn't support bare ES module imports without additional configuration. Options: + 1. **esbuild** — fast, minimal config, already used in many Electron projects 2. **Electron's native ESM support** — requires `"type": "module"` and sandbox configuration 3. **TypeScript compiler output** — if targeting a single concatenated bundle The build pipeline already compiles TypeScript and copies renderer assets. Adding a bundling step for the renderer would slot into the existing `npm run build` script. + ## Acceptance Criteria + + - [x] #1 Renderer code can be split across multiple .ts files with imports - [x] #2 Build pipeline bundles renderer modules into a single output for Electron - [x] #3 Existing `make build` still works end-to-end @@ -44,13 +49,17 @@ The build pipeline already compiles TypeScript and copies renderer assets. Addin ## Implementation Notes + Updated root npm build pipeline to use an explicit renderer bundle step via esbuild. Added `build:renderer` script to emit a single `dist/renderer/renderer.js` from `src/renderer/renderer.ts`; `build` now runs `pnpm run build:renderer` and preserves existing index/style copy and macOS helper step. Added `esbuild` to devDependencies. + ## Final Summary + Implemented renderer bundling step and wired `build` to use it. This adds `pnpm run build:renderer` which bundles `src/renderer/renderer.ts` into a single `dist/renderer/renderer.js` for Electron to load. Also added `esbuild` as a dev dependency and aligned `pnpm-lock.yaml` importer metadata for dependency consistency. Kept `index.html`/`style.css` copy path unchanged, so renderer asset layout remains stable. Implemented additional test-layer type fix after build breakage by correcting `makeDepsFromMecabTokenizer` and related `tokenizeWithMecab` mocks to match expected `Token` vs `MergedToken` shapes, keeping runtime behavior unchanged while satisfying TS checks. + diff --git a/backlog/completed/task-20.1 - Refactor-overlay-runtime-to-use-per-layer-window-bounds-ownership.md b/backlog/completed/task-20.1 - Refactor-overlay-runtime-to-use-per-layer-window-bounds-ownership.md index 4c5d59c..3f12a2b 100644 --- a/backlog/completed/task-20.1 - Refactor-overlay-runtime-to-use-per-layer-window-bounds-ownership.md +++ b/backlog/completed/task-20.1 - Refactor-overlay-runtime-to-use-per-layer-window-bounds-ownership.md @@ -14,11 +14,15 @@ priority: medium ## Description + Refactor overlay runtime so each overlay layer owns and applies its bounds independently. Keep tracker geometry as shared origin input only. + ## Acceptance Criteria + + - [x] #1 `updateOverlayBoundsService` no longer applies the same bounds to every overlay window by default. - [x] #2 Main runtime/manager exposes per-layer bounds update paths for visible and invisible overlays. - [x] #3 Window tracker updates feed shared origin data; each layer applies its own computed bounds. @@ -28,6 +32,7 @@ Refactor overlay runtime so each overlay layer owns and applies its bounds indep ## Implementation Notes + Started implementation for per-layer overlay bounds ownership refactor. Implemented per-layer bounds ownership path: visible and invisible layers now update bounds independently through overlay manager/runtime plumbing, while preserving existing geometry source behavior. @@ -35,10 +40,13 @@ Implemented per-layer bounds ownership path: visible and invisible layers now up Replaced shared all-window bounds application with per-window bound application service and layer-specific runtime calls from visibility/tracker flows. Archiving requested by user. + ## Final Summary + Refactored overlay bounds ownership to per-layer update paths. Tracker geometry remains shared input, but visible/invisible windows apply bounds independently via explicit layer routes. Existing single-layer UX behavior is preserved. + diff --git a/backlog/completed/task-27 - Refactor-project-structure-to-reduce-architectural-complexity-and-split-oversized-modules.md b/backlog/completed/task-27 - Refactor-project-structure-to-reduce-architectural-complexity-and-split-oversized-modules.md index 22a06ab..50b3f79 100644 --- a/backlog/completed/task-27 - Refactor-project-structure-to-reduce-architectural-complexity-and-split-oversized-modules.md +++ b/backlog/completed/task-27 - Refactor-project-structure-to-reduce-architectural-complexity-and-split-oversized-modules.md @@ -18,14 +18,18 @@ priority: high ## Description + Create a phased backlog-backed restructuring plan that keeps current service-oriented architecture while reducing cognitive load from oversized modules and tightening module ownership boundaries. This initiative should make future feature work easier by splitting high-complexity files, reducing tightly-coupled orchestration, and introducing measurable structural guardrails. + ## Acceptance Criteria + -- [ ] #1 A phased decomposition plan is defined in task links and references the following target files: src/main.ts, src/anki-integration.ts, src/core/services/mpv-service.ts, src/renderer/*, src/config/*, and src/core/services/*. + +- [ ] #1 A phased decomposition plan is defined in task links and references the following target files: src/main.ts, src/anki-integration.ts, src/core/services/mpv-service.ts, src/renderer/_, src/config/_, and src/core/services/\*. - [ ] #2 Tasks are assigned with clear owners and include explicit dependencies so execution can proceed in parallel where safe. - [ ] #3 Changes are constrained to structural refactors first (no behavior changes until foundational splits are in place). - [ ] #4 Each subtask includes test/verification expectations (manual or automated) and a rollback-safe checkpoint. @@ -34,27 +38,35 @@ This initiative should make future feature work easier by splitting high-complex ## Implementation Plan + ## Revised Execution Sequence ### Phase 0 — Prerequisites (outside TASK-27 tree) + - **TASK-7** — Extract main.ts global state into AppState container (required before TASK-27.2) - **TASK-9** — Remove trivial wrapper functions from main.ts (depends on TASK-7; recommended before TASK-27.2 but not blocking) ### Phase 1 — Lightweight Inventory + - **TASK-27.1** — Inventory files >400 LOC, document contracts, define smoke test checklist ### Phase 2 — Sequential Split Wave + Order matters to avoid merge conflicts: + 1. **TASK-27.3** — anki-integration.ts split (self-contained, doesn't affect main.ts wiring until facade is stable) 2. **TASK-27.2** — main.ts split (after TASK-7 provides AppState container and 27.3 stabilizes the Anki facade) 3. **TASK-27.4** — mpv-service.ts split (absorbs TASK-8 scope; blocked until 27.1 is done) 4. **TASK-27.5** — renderer positioning.ts split (downscoped; after 27.2 to avoid import-path conflicts) ### Phase 3 — Stabilization + - **TASK-27.7** — Finalization and validation cleanup ## Smoke Test Checklist (applies to all subtasks) + Every subtask must verify before merging: + - [ ] App starts and connects to MPV - [ ] Subtitle text appears in overlay - [ ] Card mining creates a note in Anki @@ -68,9 +80,11 @@ Every subtask must verify before merging: ## Implementation Notes + ## Review Findings (2026-02-13) ### Key changes from original plan: + 1. **Dropped parallel execution of Phase 2** — TASK-27.2 and 27.5 share import paths; 27.2 and 27.3 share main.ts wiring. Sequential order prevents merge conflicts. 2. **Added TASK-7 as external prerequisite** — main.ts has 30+ module-level `let` declarations. Splitting files without a state container first just scatters mutable state. 3. **TASK-8 absorbed into TASK-27.4** — TASK-8 (separate protocol from app logic) and TASK-27.4 (physical file split) overlap significantly. TASK-27.4 now covers both. @@ -82,11 +96,15 @@ Every subtask must verify before merging: ## Final Summary + TASK-27 completed: plan execution sequence completed through all major refactor subtasks. Done status now confirmed for 27.1 (ownership mapping), 27.2 (main.ts split), 27.3 (anki-integration service-domain extraction), 27.4 (mpv-service split), 27.5 (renderer positioning split), and 27.7 (final validation summary, build + tests). Remaining work is now outside TASK-27 scope. + ## Definition of Done + + - [ ] #1 Plan task links and ordering are recorded in backlog descriptions. - [ ] #2 At least 2 independent owners are assigned with explicit labels in subtasks. diff --git a/backlog/completed/task-27.7 - Decompose-anki-integration.ts-core-into-domain-modules-field-grouping-card-creation-polling.md b/backlog/completed/task-27.7 - Decompose-anki-integration.ts-core-into-domain-modules-field-grouping-card-creation-polling.md index a0ffb75..701b27e 100644 --- a/backlog/completed/task-27.7 - Decompose-anki-integration.ts-core-into-domain-modules-field-grouping-card-creation-polling.md +++ b/backlog/completed/task-27.7 - Decompose-anki-integration.ts-core-into-domain-modules-field-grouping-card-creation-polling.md @@ -25,21 +25,26 @@ priority: high ## Description + TASK-27.3 extracted leaf clusters (duplicate-detection 102 LOC, ai-translation 158 LOC, ui-feedback 107 LOC) but the core class remains at 2935 LOC. The heavy decomposition from the original TASK-27.3 plan was never executed. Remaining extractions from the original plan: + 1. **field-grouping** (~900 LOC) — `triggerFieldGroupingForLastAddedCard`, `applyFieldGrouping`, `computeFieldGroupingMergedFields`, `buildFieldGroupingPreview`, `performFieldGroupingMerge`, `handleFieldGroupingAuto`, `handleFieldGroupingManual`, plus ~15 span/parse/normalize helpers 2. **card-creation** (~350 LOC) — `createSentenceCard`, `setCardTypeFields`, `extractFields`, `processSentence`, field resolution helpers 3. **polling/lifecycle** (~250 LOC) — `start`, `stop`, `poll`, `pollOnce`, `processNewCard` Also consolidate the scattered extraction files into `src/anki-integration/`: + - `src/anki-integration-duplicate.ts` → `src/anki-integration/duplicate.ts` - `src/anki-integration-ui-feedback.ts` → `src/anki-integration/ui-feedback.ts` - `src/anki-integration/ai.ts` (already there) ## Acceptance Criteria + + - [ ] #1 anki-integration.ts reduced below 800 LOC (facade + private state wiring only) - [ ] #2 Field-grouping cluster (~900 LOC) extracted as its own module under src/anki-integration/ - [ ] #3 Card-creation and polling/lifecycle extracted as separate modules @@ -51,5 +56,7 @@ Also consolidate the scattered extraction files into `src/anki-integration/`: ## Final Summary + Implemented and stabilized the anki-integration refactor + transport/protocol fixes needed to keep 27.7 moving: fixed MPV protocol sub-end timing behavior, corrected split-buffer test fixtures, added injectable mpv transport socket factory to eliminate readonly Socket monkey-patching, and resolved TypeScript strictness issues in card-creation path (typed notesInfo cast, option signature/field guards/audio stream index). Updated related tests and build outputs accordingly. Validation results: `bun run build` passes and targeted suites pass: `src/core/services/mpv-protocol.test.ts`, `src/core/services/mpv-transport.test.ts`, `src/anki-integration.test.ts` (16/16). + diff --git a/backlog/completed/task-55 - Normalize-service-naming-conventions-across-core-services.md b/backlog/completed/task-55 - Normalize-service-naming-conventions-across-core-services.md index 4aafba5..d850811 100644 --- a/backlog/completed/task-55 - Normalize-service-naming-conventions-across-core-services.md +++ b/backlog/completed/task-55 - Normalize-service-naming-conventions-across-core-services.md @@ -15,7 +15,9 @@ priority: low ## Description + The core/services directory has inconsistent naming patterns that create confusion: + - Some files use `*Service.ts` suffix (e.g., `mpv-service.ts`, `tokenizer-service.ts`) - Others use `*RuntimeService.ts` or just descriptive names (e.g., `overlay-visibility-service.ts` exports functions with 'Service' in name) - Some functions in files have 'Service' suffix, others don't @@ -23,18 +25,23 @@ The core/services directory has inconsistent naming patterns that create confusi This inconsistency makes it hard to predict file/function names and creates cognitive overhead. Standardize on: + - File names: `kebab-case.ts` without 'service' suffix (e.g., `mpv.ts`, `tokenizer.ts`) - Function names: descriptive verbs without 'Service' suffix (e.g., `createMpvClient()`, `tokenizeSubtitle()`) - Barrel exports: clean, predictable names Files needing audit (47 services): + - All files in src/core/services/ need review Note: This is a large-scale refactor that should be done carefully to avoid breaking changes. + ## Acceptance Criteria + + - [x] #1 Establish naming convention rules (document in code or docs) - [x] #2 Audit all service files for naming inconsistencies - [x] #3 Rename files to follow convention (kebab-case, no 'service' suffix) @@ -48,6 +55,7 @@ Note: This is a large-scale refactor that should be done carefully to avoid brea ## Implementation Notes + Starting implementation. Planning and executing a mechanical refactor: file names and exported symbols with Service suffix in `src/core/services`, then cascading import updates across `src/`. Implemented naming convention refactor across `src/core/services`: removed `-service` from service file names, renamed Service-suffixed exported symbols to non-Service names, and updated barrel exports in `src/core/services/index.ts`. @@ -55,10 +63,13 @@ Implemented naming convention refactor across `src/core/services`: removed `-ser Updated call sites across `src/main/**`, `src/core/services/**` tests, `scripts/**`, `package.json` test paths, and docs references (`docs/development.md`, `docs/architecture.md`, `docs/structure-roadmap.md`). Validation completed: `pnpm run build` and `pnpm run test:fast` both pass after refactor. + ## Final Summary + Normalized `src/core/services` naming by removing `-service` from module filenames, dropping `Service` suffixes from exported service functions, and updating `src/core/services/index.ts` barrel exports to the new names. Updated all import/call sites across `src/main/**`, service tests, scripts, and docs/package test paths to match the new module and symbol names. Verified no behavior regressions with `pnpm run build` and `pnpm run test:fast` (all passing). + diff --git a/backlog/completed/task-56 - Extract-remaining-main.ts-runtime-functions-to-dedicated-modules.md b/backlog/completed/task-56 - Extract-remaining-main.ts-runtime-functions-to-dedicated-modules.md index d792c8c..e58b15b 100644 --- a/backlog/completed/task-56 - Extract-remaining-main.ts-runtime-functions-to-dedicated-modules.md +++ b/backlog/completed/task-56 - Extract-remaining-main.ts-runtime-functions-to-dedicated-modules.md @@ -15,28 +15,34 @@ priority: medium ## Description + main.ts is still 1481 lines after previous refactoring efforts. While significant progress has been made, there are still opportunities to extract runtime functions into dedicated modules to further reduce its size and improve maintainability. Current opportunities: + 1. **JLPT dictionary lookup functions** (lines 470-535) - initializeJlptDictionaryLookup, ensureJlptDictionaryLookup, getJlptDictionarySearchPaths 2. **Media path utilities** (lines 552-590) - updateCurrentMediaPath, updateCurrentMediaTitle, resolveMediaPathForJimaku 3. **Overlay visibility helpers** (lines 1273-1360) - updateVisibleOverlayVisibility, updateInvisibleOverlayVisibility, syncInvisibleOverlayMousePassthrough These functions are largely self-contained and could be moved to: + - `src/main/jlpt-runtime.ts` -- `src/main/media-runtime.ts` +- `src/main/media-runtime.ts` - `src/main/overlay-visibility-runtime.ts` Goal: Reduce main.ts complexity by extracting focused runtime helpers into dedicated modules Benefits: + - Faster navigation and comprehension of main.ts - Easier to test extracted modules independently - Clearer separation of concerns ## Acceptance Criteria + + - [x] #1 Extract JLPT dictionary lookup functions to dedicated module - [x] #2 Extract media path utilities to dedicated module - [x] #3 Extract overlay visibility helpers to dedicated module @@ -49,7 +55,9 @@ Benefits: ## Final Summary + Refactor complete for targeted runtime extraction: JLPT lookup, media utilities, and overlay visibility helpers were moved into dedicated main-runtime modules and wired from main.ts. Existing behavior preserved and full typecheck + test suite passed. Task intent updated to prioritize readability over strict line-count target. + diff --git a/backlog/completed/task-8 - Reduce-MpvIpcClient-deps-interface-and-separate-protocol-from-application-logic.md b/backlog/completed/task-8 - Reduce-MpvIpcClient-deps-interface-and-separate-protocol-from-application-logic.md index e652abf..e9ba9ca 100644 --- a/backlog/completed/task-8 - Reduce-MpvIpcClient-deps-interface-and-separate-protocol-from-application-logic.md +++ b/backlog/completed/task-8 - Reduce-MpvIpcClient-deps-interface-and-separate-protocol-from-application-logic.md @@ -21,17 +21,22 @@ priority: medium ## Description + MpvIpcClient (761 lines) in src/core/services/mpv-service.ts has a 22-property `MpvIpcClientDeps` interface that reaches back into main.ts state for application-level concerns (overlay visibility, subtitle timing, media path updates, OSD display). The class mixes two responsibilities: + 1. **IPC Protocol**: Socket connection, JSON message framing, reconnection, property observation 2. **Application Integration**: Subtitle text broadcasting, overlay visibility sync, timing tracking Separating these would let the protocol layer be simpler and testable, while application-level reactions to mpv events could be handled by listeners/callbacks registered externally. + ## Acceptance Criteria + + - [ ] #1 MpvIpcClient deps interface reduced to protocol-level concerns only - [ ] #2 Application-level reactions (subtitle broadcast, overlay sync, timing) handled via event emitter or external listeners - [ ] #3 MpvIpcClient is testable without mocking 22 callbacks @@ -41,5 +46,7 @@ Separating these would let the protocol layer be simpler and testable, while app ## Final Summary + Superseded by TASK-27.4 which absorbed this task's full scope (protocol/application separation, deps interface reduction from 22 properties to protocol-level concerns, event-based app reactions). All acceptance criteria met by TASK-27.4. + diff --git a/backlog/completed/task-9 - Remove-trivial-wrapper-functions-from-main.ts.md b/backlog/completed/task-9 - Remove-trivial-wrapper-functions-from-main.ts.md index 751bbbb..4bbb2c7 100644 --- a/backlog/completed/task-9 - Remove-trivial-wrapper-functions-from-main.ts.md +++ b/backlog/completed/task-9 - Remove-trivial-wrapper-functions-from-main.ts.md @@ -20,6 +20,7 @@ priority: low ## Description + main.ts contains many trivial single-line wrapper functions that add indirection without value: ```typescript @@ -37,10 +38,13 @@ function ensureOverlayWindowLevel(window: BrowserWindow): void { Similarly, config accessor wrappers like `getJimakuLanguagePreference()`, `getJimakuMaxEntryResults()`, `resolveJimakuApiKey()` are pure boilerplate. After TASK-7 (AppState container), many of these can be eliminated by having services access the state container directly, or by using the service functions directly at call sites without local wrappers. + ## Acceptance Criteria + + - [ ] #1 Trivial pass-through wrappers eliminated (call service/manager directly) - [ ] #2 Config accessor wrappers replaced with direct calls or a config accessor helper - [ ] #3 main.ts line count reduced @@ -50,11 +54,15 @@ After TASK-7 (AppState container), many of these can be eliminated by having ser ## Implementation Notes + Priority changed from medium to low: this work is largely subsumed by TASK-27.2 (split main.ts). When main.ts is decomposed into composition-root modules, trivial wrappers will naturally be eliminated or inlined. Recommend folding remaining wrapper cleanup into TASK-27.2 rather than tracking separately. Keep this ticket as a checklist reference but don't execute independently. + ## Final Summary + Subsumed by TASK-27.2 (main.ts split). Trivial wrappers were eliminated or inlined as composition-root modules were extracted. main.ts reduced from ~2000+ LOC to 1384 with state routed through appState container. Standalone wrapper removal pass no longer needed. + diff --git a/backlog/config.yml b/backlog/config.yml index de5fb9e..ffb9ab0 100644 --- a/backlog/config.yml +++ b/backlog/config.yml @@ -1,11 +1,11 @@ -project_name: "SubMiner" -default_status: "To Do" -statuses: ["To Do", "In Progress", "Done"] +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" +default_editor: 'nvim' auto_open_browser: false default_port: 6420 remote_operations: true @@ -13,4 +13,4 @@ auto_commit: false bypass_git_hooks: false check_active_branches: true active_branch_days: 30 -task_prefix: "task" +task_prefix: 'task' diff --git a/backlog/milestones/m-0 - release-v0.1.0.md b/backlog/milestones/m-0 - release-v0.1.0.md index 0f9a865..d878795 100644 --- a/backlog/milestones/m-0 - release-v0.1.0.md +++ b/backlog/milestones/m-0 - release-v0.1.0.md @@ -1,6 +1,6 @@ --- id: m-0 -title: "Release v0.1.0" +title: 'Release v0.1.0' --- ## Description 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 index 7e44b25..c06627a 100644 --- a/backlog/tasks/task-1 - Refactor-runtime-services-per-plan.md.md +++ b/backlog/tasks/task-1 - Refactor-runtime-services-per-plan.md.md @@ -15,11 +15,15 @@ ordinal: 2000 ## 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. @@ -29,6 +33,7 @@ Execute the SubMiner refactoring initiative documented in plan.md to reduce thin ## 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. @@ -40,10 +45,13 @@ Completed TASK-1.5 (critical behavior tests) with expanded tokenizer/mpv/subsync 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 index 18d0888..647d5de 100644 --- 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 @@ -19,11 +19,15 @@ ordinal: 12000 ## 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. @@ -33,6 +37,7 @@ Inline trivial wrapper services into their call sites and delete redundant servi ## 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. @@ -43,6 +48,7 @@ Inline trivial wrapper services into their call sites and delete redundant servi ## 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`. @@ -50,4 +56,5 @@ Deleted 16 Phase 1 files (9 wrapper services + 7 wrapper tests) and removed corr 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 index 0f3d3a9..a1d8d45 100644 --- 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 @@ -22,11 +22,15 @@ ordinal: 10000 ## 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. @@ -36,6 +40,7 @@ Absorb dependency adapter runtime services into core service modules and remove ## 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. @@ -46,6 +51,7 @@ Absorb dependency adapter runtime services into core service modules and remove ## 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. @@ -53,4 +59,5 @@ Deleted adapter service files and tests for cli-command deps, ipc deps, tokenize 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 index 971b3a3..28d224f 100644 --- 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 @@ -23,11 +23,15 @@ ordinal: 6000 ## 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. @@ -38,6 +42,7 @@ Merge split modules for overlay visibility, broadcast, shortcuts, numeric shortc ## 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. @@ -48,6 +53,7 @@ Merge split modules for overlay visibility, broadcast, shortcuts, numeric shortc ## 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`. @@ -59,4 +65,5 @@ Merged numeric shortcut runtime/session split into `numeric-shortcut-service.ts` 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 index 2513f50..2b049b6 100644 --- 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 @@ -21,11 +21,15 @@ ordinal: 3000 ## 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. @@ -37,6 +41,7 @@ Address identified correctness and code-quality issues from plan.md, including r ## 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. @@ -47,6 +52,7 @@ Address identified correctness and code-quality issues from plan.md, including r ## 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`). @@ -80,10 +86,13 @@ Automated interactive-smoke surrogate 2 (outside sandbox): started app, sent `-- 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 index 897c710..f2655ef 100644 --- 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 @@ -22,11 +22,15 @@ ordinal: 5000 ## 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. @@ -37,6 +41,7 @@ Add meaningful behavior tests for high-risk services called out in plan.md: mpv, ## 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. @@ -47,6 +52,7 @@ Add meaningful behavior tests for high-risk services called out in plan.md: mpv, ## 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`. @@ -72,4 +78,5 @@ Added subsync command-construction tests using executable stubs for both engines 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 index 2c2f1c5..22eac78 100644 --- 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 @@ -17,11 +17,15 @@ ordinal: 4000 ## 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. @@ -30,6 +34,7 @@ If service flattening remains hard to navigate after Phases 1-5, optionally move ## 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. @@ -38,9 +43,11 @@ If service flattening remains hard to navigate after Phases 1-5, optionally move ## 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/backlog/tasks/task-13 - Fix-macos-native-window-bounds-for-overlay-binding.md b/backlog/tasks/task-13 - Fix-macos-native-window-bounds-for-overlay-binding.md new file mode 100644 index 0000000..0bb3c87 --- /dev/null +++ b/backlog/tasks/task-13 - Fix-macos-native-window-bounds-for-overlay-binding.md @@ -0,0 +1,51 @@ +--- +id: TASK-13 +title: Fix macOS native window bounds for overlay binding +status: Done +assignee: + - codex +created_date: '2026-02-11 15:45' +updated_date: '2026-02-11 16:36' +labels: + - bug + - macos + - overlay +dependencies: [] +references: + - src/window-trackers/macos-tracker.ts + - scripts/get-mpv-window-macos.swift +priority: high +--- + +## Description + + + +Overlay windows on macOS are not properly aligned to the mpv window after switching from AppleScript window discovery to native Swift/CoreGraphics bounds retrieval. + +Implement a robust native bounds strategy that prefers Accessibility window geometry (matching app-window coordinates used previously) and falls back to filtered CoreGraphics windows when Accessibility data is unavailable. + + + +## Acceptance Criteria + + + +- [x] #1 Overlay bounds track the active mpv window with correct position and size on macOS. +- [x] #2 Helper avoids selecting off-screen/non-primary mpv-related windows. +- [x] #3 Build succeeds with the updated macOS helper. + + +## Implementation Notes + + + +Follow-up in progress after packaged app runtime showed fullscreen fallback behavior: + +- Added packaged-app helper path resolution in tracker (`process.resourcesPath/scripts/get-mpv-window-macos`). +- Added `.asar` helper materialization to temp path so child process execution is possible if candidate path resolves inside asar. +- Added throttled tracker logging for helper execution failures to expose runtime errors without log spam. +- Updated Electron builder `extraResources` to ship `dist/scripts/get-mpv-window-macos` outside asar at `resources/scripts/get-mpv-window-macos`. +- Added macOS-only invisible subtitle vertical nudge (`+5px`) in renderer layout to align interactive subtitles with mpv glyph baseline after bounds fix. +- Increased macOS-only invisible subtitle line-height for multi-line text to improve separation as line count grows. + diff --git a/backlog/tasks/task-13 - Fix-second-instance-start-when-texthooker-only-instance-is-running.md b/backlog/tasks/task-13 - Fix-second-instance-start-when-texthooker-only-instance-is-running.md index 68a8c48..ed1e74a 100644 --- a/backlog/tasks/task-13 - Fix-second-instance-start-when-texthooker-only-instance-is-running.md +++ b/backlog/tasks/task-13 - Fix-second-instance-start-when-texthooker-only-instance-is-running.md @@ -17,11 +17,15 @@ ordinal: 51000 ## Description + When SubMiner is already running in texthooker-only mode, a subsequent `--start` command from a second instance is currently ignored. This can leave users without an initialized overlay runtime even though startup commands were issued. Adjust CLI command handling so `--start` on second-instance initializes overlay runtime when it is not yet initialized, while preserving current ignore behavior when overlay runtime is already active. + ## Acceptance Criteria + + - [x] #1 Second-instance `--start` initializes overlay runtime when current instance has deferred/not-initialized overlay runtime. - [x] #2 Second-instance `--start` remains ignored (existing behavior) when overlay runtime is already initialized. - [x] #3 CLI command service tests cover both behaviors and pass. @@ -30,23 +34,28 @@ When SubMiner is already running in texthooker-only mode, a subsequent `--start` ## Implementation Notes + Patched CLI second-instance `--start` handling in `src/core/services/cli-command-service.ts` to initialize overlay runtime when deferred. Added regression test for deferred-runtime start path and updated initialized-runtime second-instance tests in `src/core/services/cli-command-service.test.ts`. + ## Final Summary + Fixed overlay startup regression path where a second-instance `--start` could be ignored even when the primary instance was running in texthooker-only/deferred overlay mode. Changes: + - Updated `handleCliCommandService` logic so `ignoreStart` applies only when source is second-instance, `--start` is present, and overlay runtime is already initialized. - Added explicit overlay-runtime initialization path for second-instance `--start` when runtime is not initialized. - Kept existing behavior for already-initialized runtime (still logs and ignores redundant `--start`). - Added and updated tests in `cli-command-service.test.ts` to validate both deferred and initialized second-instance startup behaviors. Validation: + - `pnpm run build` succeeded. - `node dist/core/services/cli-command-service.test.js` passed (11/11). diff --git a/backlog/tasks/task-14 - Ensure-subminer-launcher-shows-visible-overlay-on-startup.md b/backlog/tasks/task-14 - Ensure-subminer-launcher-shows-visible-overlay-on-startup.md index e2bf71f..7630a8c 100644 --- a/backlog/tasks/task-14 - Ensure-subminer-launcher-shows-visible-overlay-on-startup.md +++ b/backlog/tasks/task-14 - Ensure-subminer-launcher-shows-visible-overlay-on-startup.md @@ -17,11 +17,15 @@ ordinal: 50000 ## Description + The `subminer` launcher starts SubMiner with `--start` but can leave the visible overlay hidden when runtime config defers auto-show (`auto_start_overlay=false`). Update launcher command args to explicitly request visible overlay at startup so script-mode behavior matches user expectations. + ## Acceptance Criteria + + - [x] #1 Running `subminer