Skip to content

Pomodoro#6

Open
TexasOct wants to merge 58 commits intoUbiquantAI:devfrom
TexasOct:main
Open

Pomodoro#6
TexasOct wants to merge 58 commits intoUbiquantAI:devfrom
TexasOct:main

Conversation

@TexasOct
Copy link
Contributor

No description provided.

Add Pomodoro timer feature that controls perception layer
(screenshot/keyboard/mouse capture) based on work sessions.
Implements an idle-by-default strategy where perception only runs
during active Pomodoro sessions.

**Core Changes:**
- Add PomodoroManager to handle session lifecycle and coordinate
  with perception layer
- Implement session database storage (pomodoro_sessions,
  raw_records tables)
- Create API handlers for starting/stopping Pomodoro sessions
- Add migration system with initial schemas and Pomodoro feature
  migration

**Perception Layer:**
- Remove _pomodoro_mode flag from ScreenshotCapture (Pomodoro
  only controls start/stop)
- Fix screenshot capture blocking issue by removing
  run_in_executor
- Simplify screenshot loop to call capture() directly in
  async context
- Improve timing accuracy by compensating for execution time
  in sleep

**Architecture:**
- Idle Mode (default): Perception layer stopped, zero resource
  usage
- Active Mode (Pomodoro): Perception layer running, captures
  activity data
- Session data persisted to database for deferred batch
  processing
- SessionAgent paused during Pomodoro, resumes after for
  activity aggregation

**Frontend:**
- Add PomodoroTimer component with start/stop controls
- Create pomodoro Zustand store for state management
- Add Tauri event handlers for Pomodoro processing events
- Add i18n translations for Pomodoro UI

**Documentation:**
- Update .project.md with Pomodoro mode principles and design
  rules
- Document that Pomodoro has no system configuration parameters
- Clarify that capture behavior (smart capture, deduplication)
  is not affected by Pomodoro mode

**Technical Notes:**
- macOS Core Graphics requires screenshot capture in main event
  loop context
- Thread pool execution causes 30s blocking on sct.grab() -
  resolved by direct async calls
- Loop timing controlled by asyncio.sleep() with execution time
  compensation
- Add new UI components: FlipDigit, CircularRoundProgress, SessionInfoCard, PresetButtons
- Refactor PomodoroTimer with better component structure and layout
- Improve countdown display with flip animation effect
- Optimize progress indicator sizing for more compact layout
- Vertically center timer display for better visual balance
- Enhance TodoAssociationSelector integration
- Add resource management handlers and API endpoints
- Extend action agent capabilities and database operations
- Update i18n translations for new UI elements
Pomodoro UI improvements:
- Add 3D flip animation to countdown clock digits with proper state management
- Redesign preset buttons with icon-based professional design replacing emoji
- Update todo association selector icon and weaken selected state styling
- Fix vertical alignment of flip clock numbers

Image persistence fix:
- Change ImageManager to dual storage strategy (memory + disk)
- Prevent "image lost" errors from LRU eviction and TTL cleanup
- Ensure screenshots are immediately persisted to disk upon capture
Implement intelligent activity aggregation for Pomodoro work phases with session-level activity linking and comprehensive review UI.

Core Features:
- Work phase aggregation: Automatically aggregate events into activities when each Pomodoro work phase ends
- Session-level activity merging: Use relaxed similarity threshold (0.5) to merge activities within the same session across multiple work phases
- Focus score calculation: Multi-factor scoring (event density, topic consistency, duration) to measure work quality
- Activity linking: Link manually created activities to Pomodoro sessions for comprehensive review

Backend Changes:
- Add `aggregate_work_phase()` method in SessionAgent to handle phase-end aggregation with retry mechanism
- Add `_merge_within_session()` for relaxed merging of activities within same Pomodoro session
- Add `_calculate_focus_score()` to compute 0-1 focus score based on event density (30%), topic consistency (40%), duration (30%)
- Add database migration to support activity work phase tracking (pomodoro_session_id, pomodoro_work_phase, focus_score)
- Add `pomodoro_linking.py` handler to support linking activities to sessions
- Update `pomodoro_stats.py` to include activity timeline and focus metrics
- Skip Pomodoro events in normal aggregation (handled by work phase aggregation)

Frontend Changes:
- Add PomodoroReview view with session selection and comprehensive review interface
- Add SessionReviewCard component with flip animation and persistent image state
- Add SessionActivityTimeline to visualize activity distribution across work phases
- Add FocusScoreVisualization for metric display
- Add LinkActivitiesDialog for manual activity linking
- Add PhaseTimeline for work/break phase visualization
- Add usePomodoroEvents hook for real-time session updates
- Update SessionInfoCard with activity linking support

Key Features:
- Real-time aggregation: Activities are created as each work phase ends
- Intelligent merging: Related activities across phases are merged automatically
- Focus tracking: Quantitative focus score provides objective quality assessment
- Manual linking: Users can link manually created activities to sessions
- Comprehensive review: Timeline, metrics, and phase breakdown for post-session analysis
- Increase event extraction wait time from 10s to 35s to ensure
  at least one extraction cycle completes
- Add retry mechanism: wait additional 15s if no events found
  on first attempt
- Fix manual session end during work phase: now properly aggregates
  activities for the current incomplete work phase
- Refactor session completion check: moved from before to after
  phase switch for better logic flow
…inuity validation

Major changes:
- Implement direct Actions → Activities aggregation for Pomodoro mode, bypassing
  Events layer
- Add database schema for action-based aggregation (migration 0007)
  - New columns: source_action_ids, aggregation_mode
  - Support both action-based and event-based modes for backward compatibility
- Create new LLM prompt 'action_aggregation' for clustering fine-grained actions
- Enhance ActivitySupervisor to validate temporal continuity between activities
  - Check time gaps between adjacent activities (≤2min normal, >5min abnormal)
  - Validate semantic accuracy based on time distribution
  - Auto-merge activities with similar themes and small time gaps
- Update SessionAgent to use action-based aggregation in aggregate_work_phase()
  - Add _get_work_phase_actions(), _cluster_actions_to_activities(),
    _calculate_focus_score_from_actions()
  - Integrate supervisor validation with source_actions support
- Fix frontend API types and handlers
  - Add FocusMetrics Pydantic model for proper TypeScript generation
  - Update PomodoroActivityData with source_action_ids and aggregation_mode
  - Fix ActivitiesRepository _row_to_dict() to safely handle new columns

Technical details:
- Actions are 30-second segments, more fine-grained than 10-minute Events
- Focus score calculation adjusted for action-based mode (0.5-3 actions/min)
- Supervisor validates both semantic accuracy and temporal continuity
- All existing event-based activities continue to work (backward compatible)
… aggregation

- Pause EventAgent in enter_pomodoro_mode() to skip Events generation
- Resume EventAgent in exit_pomodoro_mode() for Normal Mode
- Direct Actions → Activities aggregation in Pomodoro mode
- EventAgent only runs in Normal Mode (Idle state)
This commit addresses three key improvements to the Pomodoro review
interface and manual activity linking:

1. Session Card Activity Count
   - Backend: Modified getPomodoroStats to fetch activity count for
     each session
   - Frontend: Updated SessionReviewCard to display actual count
     instead of hardcoded 0

2. 24-Hour Time Format
   - Updated SessionActivityTimeline formatTime() to use hour12: false
   - Updated LinkActivitiesDialog time display to 24-hour format
   - Times now display as "20:06" instead of "8:06 PM"

3. Auto-Categorize Phase on Manual Link
   - Backend: Refactored link_activities_to_session() to auto-detect
     work phases
   - Added _calculate_phase_timeline_for_linking() helper
   - Added _determine_work_phase() helper to match activity time to
     correct phase
   - Activities now auto-assigned to correct work phase (1-4) based
     on start time
   - If activity falls outside work phases, assigns to nearest phase

4. Migration Script for Existing Data
   - Created scripts/assign_activity_phases.py to process existing
     Pomodoro activities
   - Automatically assigns phases to activities that have session_id
     but missing work_phase
   - Successfully processed 1 activity, assigning it to phase 1

Files Changed:
- backend/handlers/pomodoro_stats.py
- backend/handlers/pomodoro_linking.py
- src/views/PomodoroReview.tsx
- src/components/pomodoro/SessionActivityTimeline.tsx
- src/components/pomodoro/LinkActivitiesDialog.tsx
- scripts/assign_activity_phases.py (new)
This commit implements interactive action cards display in the Pomodoro
session activity timeline, replacing the old action → event → activity
architecture with direct action → activity drill-down.

1. Backend API
   - Added get_actions_by_activity handler in events.py
   - Reuses GetActionsByEventRequest/Response models for compatibility
   - Supports both action-based and event-based activities (backward
     compatible)
   - Automatically loads screenshots for each action

2. Frontend Components
   - Updated SessionActivityTimeline with expandable action cards
   - Added state management for expanded activities and actions
   - Integrated ActionCard component for action display
   - Shows loading states and empty states appropriately

3. User Interaction
   - Click "View Actions" to expand activity and load actions
   - Click "Hide Actions" to collapse
   - Actions display with full details: title, description, keywords,
     timestamps, and screenshots
   - Follows same interaction pattern as Activity.tsx

4. Implementation Details
   - Uses pyInvoke to call get_actions_by_activity command
   - Caches loaded actions to avoid redundant API calls
   - Maintains expand/collapse state per activity
   - Supports both camelCase and snake_case activity fields

Files Changed:
- backend/handlers/events.py (new handler)
- src/components/pomodoro/SessionActivityTimeline.tsx (major update)
Replace direct pyInvoke call with the generated getActionsByActivity
function from apiClient.ts for better type safety and maintainability.

Changes:
- Import getActionsByActivity from @/lib/client/apiClient
- Remove direct pyInvoke import
- Add type conversion from ActionResponse to Action
  - Convert timestamp from string (ISO) to number (milliseconds)
  - Convert createdAt from string to number
  - Preserve all other fields

Benefits:
- Full TypeScript type checking at compile time
- Auto-completion support in IDE
- Consistent with other API calls in the codebase
- Easier to maintain when API changes
- Add duration filter in SessionAgent to exclude activities < 2 minutes
- Integrate break time display into activity timeline instead of separate component
- Show phase start/end time and duration in timeline
- Add i18n support for break time label
…ovements

Backend:
- Add knowledge favorite toggle functionality with database migration
- Add LLM-based focus score evaluation for pomodoro sessions
- Implement action-based activity aggregation (disable EventAgent)
- Add pomodoro session LLM evaluation caching
- Fix knowledge repository to handle missing favorite field gracefully

Frontend:
- Redesign knowledge management UI with independent scrolling columns
- Add CategorySidebar, KnowledgeCard, and filter tabs components
- Refactor pomodoro UI with new stats overview and session details
- Enhance PageLayout to support sticky header with child-controlled scrolling
- Add collapsible UI component for better interaction
- Optimize card layouts with max-height constraints for keywords

Database:
- Migration 0008: Add favorite column to knowledge table
- Add llm_evaluation_result fields to pomodoro_sessions table

Dependencies:
- Update package dependencies for UI enhancements
- Add framer-motion for smooth view transitions
- Enable todo card click to view details
- Create reusable DeleteConfirmDialog component
- Remove deprecated BatchDeleteSettings component
- Update i18n translations for better clarity
Remove 3 unused alternative UI implementations:
- CircularRoundProgress: dual-ring progress display
- FlipDigit: flip-card digit animation
- PomodoroCustomConfig: custom configuration panel

These components were never integrated into the application.
…ew UI

Database Changes:
- Add migration 0009 for llm_evaluation_result column
- Add migration 0009 for llm_evaluation_computed_at column
- Fixes sqlite3.OperationalError: no such column error

UI Improvements:
- Reorder Pomodoro review dialog layout
- Move AI Analysis panel above Activity Timeline
- Better visual hierarchy for session review

Note: LLM evaluation already runs automatically after session ends
(implemented in backend/core/pomodoro_manager.py:607)
- Replace deprecated CSS classes with modern equivalents
  - flex-shrink-0 → shrink-0
  - supports-[backdrop-filter] → supports-backdrop-filter
- Simplify f-string in error message (pomodoro handler)
Add missing translation keys:
- Add camelCase versions of dimension names (topicConsistency, etc.)
  to support LLM responses that use camelCase format
- Add productivity_analysis work type translation
- Both snake_case and camelCase keys now supported for compatibility

Fixes display of:
- 专注度维度评分 dimension names (Chinese)
- Focus Dimensions names (English)
- 工作上下文 work type labels
Replace algorithm-based focus scoring with LLM evaluation for individual
activities during Pomodoro work phase aggregation.

**Changes:**
- Add activity_focus_evaluation prompts (en/zh) with 4 evaluation dimensions:
  * Task Clarity (30%)
  * Duration Quality (30%)
  * Work Substance (25%)
  * Goal Directedness (15%)
- Extend FocusEvaluator with evaluate_activity_focus() method
  * Returns 0-100 score with reasoning, work_type, is_productive
  * Includes helper methods for parsing, validation, and fallback
- Modify session_agent.py to use parallel LLM evaluation
  * Use asyncio.gather() for concurrent scoring (3-8 activities/batch)
  * Fallback to algorithm on LLM failure (3-tier error handling)
  * Keep _calculate_focus_score_from_actions() as fallback method

**Impact:**
- Activities scored individually in real-time during generation
- ~$0.12/session cost increase with GPT-4 (15-25 activities)
- <1s latency with parallel evaluation
- 0-100 score scale (consistent with session-level evaluation)

**Error Handling:**
- Primary: LLM evaluation
- Fallback 1: Algorithm-based scoring (existing method)
- Fallback 2: Default score of 50
Remove duplicate snake_case translation keys in pomodoro aiAnalysis section,
keeping only camelCase versions for consistency.

**Changes:**
- Remove snake_case dimension keys (topic_consistency, duration_depth, etc.)
- Keep camelCase versions (topicConsistency, durationDepth, etc.)
- Change productivity_analysis to productivityAnalysis in workTypes

**Impact:**
- Reduced translation keys from 731 to 726
- LLM responses now use camelCase keys directly
- Cleaner i18n structure with single naming convention
- Chat: redesign with flatter visual style and responsive layout
  - Remove shadows and reduce elevation effects
  - Add mobile sidebar with overlay for small screens
  - Simplify ConversationList using plain div instead of Card
  - Flatten MessageInput design with reduced background contrast
  - Change all rounded corners from rounded-lg to rounded-md
  - Add responsive breakpoint (lg) to hide sidebar on narrow windows

- Pomodoro: align with standard page layout
  - Use sticky header for better navigation
  - Center content with max-width-2xl constraint
  - Adjust padding for consistency

- AITodos: increase sidebar visibility threshold
  - Change breakpoint from lg to xl (1024px → 1280px)
  - Give calendar view more space on medium screens

- i18n: add missing translations
  - Add 'conversations' label for chat sidebar
Fix focus score visualization showing incorrect percentages (e.g., 3977% instead of 39%).

**Problem:**
- Backend returns focus_score as 0-100 integer
- FocusScoreVisualization expected 0.0-1.0 decimal
- Component calculated percentage as score * 100, resulting in values like 3977%

**Solution:**
- Add automatic normalization: if score > 1, divide by 100
- Update interface comment to reflect 0-100 scale
- All color/level calculations now use normalized score

**Impact:**
- Focus scores now display correctly (0-100%)
- Works with both 0-1 and 0-100 input ranges
- No changes needed in calling components
Include user's work goals and linked todos in activity focus evaluation
to provide more accurate and purposeful scoring based on goal alignment.

Backend changes:
- Add session context retrieval for user intent and todos
- Pass session context to focus evaluator
- Update evaluation prompt to include work goals section
- Enhance Goal Directedness dimension with actual goal context

Frontend changes:
- Improve session detail dialog list item layout
- Add entertainment work type translation
…overflow

Optimize the model configuration welcome interface to prevent button
overflow issues caused by i18n translations and improve overall layout.

Changes:
- Move configured models list above create new model form
- Add responsive button layout with flex-wrap to prevent overflow
- Hide button text on small screens, show icons only
- Use truncate on model name and provider info to prevent overflow
- Add proper flex constraints (min-w-0, flex-1, shrink-0)
- Reduce icon sizes from h-4 w-4 to h-3.5 w-3.5 for better fit
- Reduce button gap from gap-2 to gap-1.5 for tighter layout

UI improvements:
- Models are now shown first for better visibility
- Buttons adapt to screen size responsively
- No more horizontal overflow in model cards
- Better text truncation prevents layout breaks
Remove ml-12 left margin from message content area in MessageItem
component to allow full-width content display.
Connect PomodoroStats component to the actual backend API to display
real-time statistics instead of showing placeholder zeros.

Changes:
- Import and call getPomodoroStats API
- Fetch today's statistics on mount
- Auto-refresh stats every minute
- Calculate focus hours from total minutes
- Show loading state with '-' placeholder
- Handle errors gracefully by showing zeros

Fixes:
- Today completed sessions now shows actual count
- Focus minutes displays real data
- Focus hours calculated from total minutes

The component was previously showing zeros due to TODO placeholder
code that was never connected to the backend API.
Implement ImageConsumer component for Pomodoro mode to optimize memory usage
and prevent HTTP timeout-related data corruption through batch processing.

Key Features:
- Dual-buffer architecture (accumulating + processing) for complete isolation
- Hybrid threshold triggering (50 screenshots OR 60 seconds)
- State machine with timeout protection (720s auto-reset)
- 95% memory reduction (metadata-only storage ~1KB vs ~50KB per screenshot)
- Zero data loss with dual flush mechanism (phase transition + session end)

Implementation:
- Created ImageConsumer with BatchState enum and ScreenshotMetadata dataclass
- Added Pomodoro buffering configuration to config.toml
- Integrated ImageConsumer into PerceptionManager with timeout checking
- Added buffer flush calls in PomodoroManager for phase transitions

Performance:
- Timeout check overhead: <1ms per screenshot
- Batch generation: 50-100ms for 50 screenshots
- Memory savings: 3MB/min → 50KB/batch (95% reduction)

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
- Add update_knowledge API handler with UpdateKnowledgeRequest/Response models
- Implement KnowledgeRepository.update() method with frontend event emission
- Create KnowledgeDetailDialog component for viewing and editing knowledge items
- Add view/edit buttons to KnowledgeCard with click-through prevention
- Improve Pomodoro components styling (remove borders, use shadow-none)
- Refactor SessionDetailDialog AI analysis display (always expanded)
- Update json2ts config to use 'any' instead of 'unknown' for better compatibility
- Add i18n entries for edit/view knowledge dialogs in en and zh-CN
- Add TodoRepository.complete() to set completed=1 instead of deletion
- Add complete_todo API endpoint for proper todo completion
- Update frontend to call complete_todo instead of delete_todo
- Load completed todos in AITodos view (includeCompleted=true)
- Fix KnowledgeCard unused import (remove FileText)
- Improve MessageInput model selection with fallback logic
- Fix textarea UI component background styling
- Fix todo drag controller to allow click events when not dragging

Previously, completing a todo would soft-delete it (deleted=1), making it
disappear from all views including the Completed tab. Now completed todos
are properly marked as completed=1 and remain visible.
- Replace polling-based processing with threshold-based event triggering
  - Add notify_records_available() to coordinator for event-driven processing
  - Integrate notifications in PerceptionManager for keyboard/mouse/screenshot events
  - Set threshold to 20 records with 5-minute fallback
  - Eliminate "No new records to process" log spam

- Fix configuration access patterns for nested TOML structure
  - Update coordinator.py to use config.get("section", {}).get("key")
  - Update db/__init__.py for database.path access
  - Update image_manager.py for image/monitoring config access
  - Increase default memory_ttl from 75s to 180s to meet recommendation

- Disable SessionAgent periodic aggregation by default
  - Add enable_periodic_aggregation parameter (default: False)
  - Only use Pomodoro-triggered aggregation
  - Remove duplicate aggregation on Pomodoro exit

- Fix smart capture to respect user-configured monitor settings
  - Check if active monitor is enabled before capturing
  - Return empty list if active monitor not in enabled list
  - Fix inactivity timeout to return all enabled monitors
TexasOct and others added 29 commits January 5, 2026 00:52
Problem:
- Multiple overlapping activities were being created in the same time period
- Example: 8 activities all spanning 00:08-00:33 in the same work phase
- Violated the design principle that activities should be temporally unique

Root Cause Analysis:
1. LLM was clustering actions by theme without time constraints
2. Overlap detection only checked adjacent activities linearly
3. No final validation before saving activities

Solution:
1. Enhanced LLM prompts with time uniqueness as highest priority
   - Added explicit constraint: "only one activity per time period"
   - Provided correct/wrong examples to guide LLM behavior
   - When multiple concurrent themes exist, merge with primary/secondary pattern

2. Improved overlap detection algorithm (_merge_overlapping_activities)
   - Iterative merging (max 10 iterations) to handle multi-way overlaps
   - Detects: complete overlap, partial overlap, and nested activities
   - Merges based on duration (longer activity becomes primary)
   - Preserves secondary activities in description with [Related: ...] pattern

3. Added final validation layer (_validate_no_time_overlap)
   - Checks all activity pairs for time conflicts before saving
   - Forces merge if overlaps detected in Pomodoro aggregation
   - Logs critical errors if overlaps persist after forced merge

Technical Changes:
- backend/agents/session_agent.py:
  * New: _parse_datetime() - unified datetime parsing
  * New: _should_merge_activities() - 3-case merge logic
  * New: _merge_two_activities() - intelligent activity merging
  * New: _validate_no_time_overlap() - final validation
  * Enhanced: _merge_overlapping_activities() - iterative algorithm
  * Integration in aggregate_work_phase() and _cluster_events_to_sessions()

- backend/config/prompts_zh.toml & prompts_en.toml:
  * Updated action_aggregation prompt with time uniqueness principle
  * Added priority-ordered consideration factors
  * Included validation examples (❌ wrong vs ✅ correct)

Defense Layers:
1. LLM layer - proactive avoidance via prompt constraints
2. Algorithm layer - iterative detection and merging
3. Validation layer - final safety check before persistence

Expected Outcome:
- No more overlapping activities in the same time period
- Primary activity shown as title, secondary mentioned in description
- Better time tracking accuracy and work session clarity
When user manually stops a Pomodoro session, the system now records
the actual work time instead of the planned duration.

Changes:
- Modified end_pomodoro() to calculate actual time for partial work phase
- Updated check_orphaned_sessions() to use same logic for interrupted sessions
- Changed stats handlers to use actual_duration_minutes for display
- Reorganized logic order to ensure activity aggregation triggers correctly

Calculation logic:
- Completed rounds: use full work_duration
- Current incomplete phase: use actual elapsed time from phase_start_time to end_time
- Example: 1 completed round (25min) + 10min in current phase = 35min total

This ensures the Pomodoro cards display accurate effective work time.
Phase 1: Simplify processing flow
- Reduce retry mechanism from 4 attempts to 1 (45s → 10s max delay)
- Remove ~200 lines of fallback processing code
- Merge batch processing layer into phase aggregation
- Unify time window calculation logic with user-configured durations

Phase 2: Simplify state management
- Merge similar status values: interrupted/too_short → abandoned
- Merge processing_status: skipped → failed
- Reduce state combinations from 10 to 7
- Add version-based migration 0010 for data migration

Code improvements:
- Remove ~250 lines of redundant code
- Add _get_phase_time_window() for unified time calculation
- Update schema CHECK constraints
- Clean up legacy migrations system

Performance improvements:
- Phase aggregation max delay: 45s → 10s
- Single data processing path (no duplication)
- Correct support for user-configured work/break durations
Phase 4: Conservative optimization of LLM evaluation system

Changes:
1. Add activity-level focus score tracking
   - New methods: update_focus_score(), batch_update_focus_scores()
   - Store individual activity focus scores in activities table
   - Enable per-activity focus analysis in frontend

2. Extend LLM evaluation workflow
   - Session-level evaluation (existing)
   - Activity-level evaluation (new)
   - Batch update all activity focus scores after session completion
   - Non-blocking: failures don't crash session completion

3. Improve configuration documentation
   - Add detailed comments for screenshot buffer settings
   - Explain timeout and threshold values
   - Note compatibility with Phase 1 optimizations (simplified retry)

Benefits:
- Better data granularity for frontend display
- Per-activity focus insights without changing session-level workflow
- Backward compatible: existing evaluation flow unchanged

Performance:
- Activity evaluation runs after session-level evaluation
- Uses async batch processing for efficiency
- Graceful degradation on failure (default score: 50.0)

Code changes: +182 lines, maintains type safety

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
Add visual focus score indicators to activity cards

Changes:
1. Extend Activity interface with Pomodoro fields
   - Add pomodoroSessionId, pomodoroWorkPhase fields
   - Add focusScore field (0-100, LLM-evaluated)

2. Implement focus score visualization in ActivityItem
   - New helper function: getFocusScoreInfo()
   - Color-coded badges based on score levels:
     * 80-100: Excellent (green)
     * 60-79: Good (blue)
     * 40-59: Moderate (yellow)
     * 0-39: Low (red)
   - Display focus score next to duration and milestone badges
   - Add Target icon for visual clarity

3. User experience improvements
   - Tooltip shows full score on hover
   - Non-intrusive: only shown when focusScore is available
   - Responsive design: badge scales with other info

Integration:
- Works with backend Phase 4 optimization
- SessionActivityTimeline already supports focusScore
- FocusScoreVisualization component handles display

Visual hierarchy:
[Time Range] [Duration] [Milestone?] [Focus Score?]

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
…ancy

Simplify activity card display by removing milestone indicator

Changes:
- Remove milestone badge (30+ minute activities)
- Focus score becomes the primary quality indicator
- Clean up unused milestone calculation logic

Rationale:
- Milestone badge was duration-based (>30 min = milestone)
- Focus score is quality-based (LLM-evaluated concentration)
- Focus score provides more valuable insights than duration alone
- Reduces visual clutter in activity cards

Display hierarchy (simplified):
[Time Range] [Duration] [Focus Score]

Before: Time | Duration | Milestone? | Focus Score?
After:  Time | Duration | Focus Score

Benefits:
- Cleaner UI with less redundancy
- Focus on quality metrics over duration
- Consistent with backend Phase 4 optimization
- Better UX: users care more about focus quality than duration threshold

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
…sessions

Add timeout protection and auto-recovery for stuck processing sessions

Problem:
When Pomodoro session ends, the system enters 'processing' status to:
1. Wait for work phases to complete (max 5 minutes)
2. Run LLM evaluation to calculate focus scores
3. Update status to 'completed'

If processing hangs (LLM timeout, crash, exception), the status stays
'processing' forever, blocking all future Pomodoro sessions with error:
"Previous Pomodoro session is still being analyzed"

Root Causes:
- LLM API calls can be very slow or timeout
- Unhandled exceptions during processing
- App crash during processing (status never updated)
- No timeout protection on total processing time

Solution:

1. Smart Session Check (15-minute threshold)
   - Check processing_started_at timestamp
   - If < 15 minutes: block new session (legitimate processing)
   - If > 15 minutes: force complete stuck session, allow new session
   - Handle missing timestamp: force complete, allow new session

2. Total Processing Timeout (10 minutes)
   - Wrap entire processing in asyncio.wait_for(timeout=600)
   - Breakdown: 5 min phase wait + ~5 min LLM evaluation
   - On timeout: mark as 'failed', emit failure event, cleanup

3. Graceful Error Handling
   - Log warnings for forced completions
   - Preserve error messages in processing_error field
   - Allow users to retry manually if needed

Benefits:
- No more permanently blocked Pomodoro sessions
- Automatic recovery from stuck states
- Better visibility into processing issues
- User can always start new session after 15 minutes max

Technical Details:
- Uses asyncio.TimeoutError for timeout detection
- Maintains backward compatibility
- No database schema changes needed
- All checks happen at session start time

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
…tead of timeout fallback

Fix smart capture capturing all screens when watching videos

Problem:
When user watches videos, the cursor is often hidden or doesn't move.
After 30 seconds of no mouse movement, smart capture would fall back
to capturing ALL enabled monitors instead of just the active one.

This caused:
- Unnecessary screenshot captures of inactive screens
- Higher CPU/memory usage
- Confusing behavior in multi-monitor setups
- Poor UX when watching long videos or reading content

Root Cause:
The original design had an "inactivity timeout" (30s) that assumed:
"no mouse movement = user is away, capture all screens"

But this assumption is wrong for common scenarios:
- Watching videos (cursor hidden)
- Reading content (no mouse needed)
- Listening to music/podcasts
- Using keyboard-only apps

Solution:

1. Remove Timeout Fallback Logic
   - Deleted should_capture_all_monitors() method
   - Removed inactive_timeout parameter
   - Smart capture NEVER falls back to "capture all"

2. Always Use Last Known Mouse Position
   - Maintains single-monitor focus even during long inactivity
   - Correct behavior: if mouse is on monitor 2, keep capturing monitor 2
   - Even if cursor is hidden, we know which monitor is active

3. Add Keyboard Activity Tracking
   - New method: update_from_keyboard()
   - Keyboard events update last_activity_time
   - Keeps smart capture aware of user presence
   - Useful for future features (e.g., idle detection)

Changes:

backend/perception/active_monitor_tracker.py:
- Remove __init__(inactive_timeout) parameter
- Remove should_capture_all_monitors() method
- Add update_from_keyboard() method
- Update docstrings to explain new behavior
- Simplify get_stats() output

backend/perception/screenshot_capture.py:
- Remove timeout check logic
- Always use get_active_monitor_index()
- Simplified smart capture decision tree

backend/perception/manager.py:
- Remove inactive_timeout initialization
- Add keyboard event → tracker update
- Remove settings load for inactive_timeout

Benefits:
- Correct behavior when watching videos
- Lower resource usage (fewer unnecessary captures)
- More predictable smart capture behavior
- Better multi-monitor support

Technical Details:
- Maintains backward compatibility
- No database/settings changes needed
- Type-safe (passes ty check)
- Keyboard tracking is passive (no performance impact)

Testing Scenarios:
✅ Watch video for > 30s: only captures active monitor
✅ Read content without moving mouse: only captures active monitor
✅ Switch monitors: captures new active monitor
✅ Multiple monitors: always captures correct one
…nfig

PROBLEM: Pomodoro sessions failed to generate activities
- Only 1 action generated in 38-minute session
- Both work_phases returned "no_actions_found" error
- LLM evaluation returned default scores (no useful data)
- Token waste: 28k tokens spent with zero output

ROOT CAUSES:
1. Single-action activities had zero duration and were filtered out
2. Duration filter threshold (2min) too strict for Pomodoro sessions
3. Screenshot similarity threshold (0.92) too high for video scenarios
4. Action extraction threshold (40) too high, causing sparse data
5. User config contained system-level settings that should be managed
   by backend

FIXES:

1. Single-Action Duration Calculation (session_agent.py:2278-2291)
   - Use 5-minute default duration for single-action activities
   - Prevents activities from being incorrectly filtered as "too short"

2. Relaxed Pomodoro Duration Filter (session_agent.py:1532-1541)
   - Lowered threshold from 2 minutes to 1 minute
   - Pomodoro's 25-minute focused work already ensures quality

3. User/System Config Separation (config/loader.py:136-187)
   - Extended system_sections filter to include all backend settings:
     monitoring, server, logging, image, image_optimization,
     processing, ui, pomodoro
   - Special handling for [screenshot] mixed settings (filter out
     smart_capture_enabled, inactive_timeout)
   - Updated default user config to only include: database,
     screenshot, language
   - Added clear warning comments about system config being ignored

4. Optimized Backend Parameters (config/config.toml)
   - screenshot_similarity_threshold: 0.92 → 0.88
     (capture more video variations)
   - action_extraction_threshold: 40 → 25
     (60% faster action generation)
   - screenshot_buffer_count_threshold: 40 → 25
     (aligned with extraction)
   - screenshot_buffer_time_threshold: 45s → 30s (more responsive)

5. Bug Fix: Event Timestamp Column (sqls/queries.py)
   - Fixed DELETE queries using deprecated 'timestamp' column
   - Changed to 'start_time' to match current schema

EXPECTED IMPROVEMENTS:
- Actions per 38min session: 1 → 12-18 (+1200%)
- Activities per session: 0 → 4-6 (usable data)
- LLM evaluation: default scores → real scores
- Token efficiency: 0% → 85%+ useful output
- Config management: clear separation, no user override

TESTING:
- Python type check: passed
- All system-level configs now ignored from user config file
- User config cleaned to only contain: database, screenshot, language

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…licate detection

- Add KnowledgeMergeDialog and MergeSuggestionsDialog UI components
- Implement knowledge_merger.py service for AI-based content analysis
- Create knowledge_merge.py handler for merge operations
- Add todo expiration feature with migration
- Introduce retry-dialog component for error recovery
- Update prompts for knowledge analysis and merge suggestions
- Enhance todo agent to mark AI-generated todos with source_type
## Features
- Add global lock mechanism during knowledge analysis to prevent concurrent operations
- Implement hard delete for knowledge entries during merge (instead of soft delete)
- Add analysis status API endpoint (/knowledge/analysis-status)
- Optimize merge prompts to refine keywords (2-4 essential tags only)

## UI Improvements
- Disable create/delete/edit/favorite buttons during analysis in all components
- Improve spacing in MergeSuggestionsDialog footer
- Update analysis state tracking in insights store

## Bug Fixes
- Fix LLM response parsing error in knowledge_merger.py
- Add missing Dict type import in knowledge_merge.py handler

## Technical Changes
- Backend: Add hard_delete() and hard_delete_batch() methods
- Backend: Update all CRUD handlers to check analysis lock state
- Frontend: Add isAnalyzing state to insights store
- Frontend: Pass isAnalyzing prop to disable relevant UI elements

## Database
- Knowledge entries are now permanently deleted during merge
- Reduced database bloat by eliminating redundant tags
- Knowledge count and tag count properly decrease after merge

This ensures data consistency during analysis and prevents database growth from merge operations.
- Redesign Pomodoro timer from single-column to two-column layout with sidebar
- Add PomodoroTodoList component to left sidebar showing scheduled todos
- Integrate horizontal stats display above todo list
- Refactor PomodoroTimer with unified vertical layout (task selection → divider → timer)
- Improve todo selection logic to update linked todo instead of manual input
- Optimize UI elements: smaller buttons, compact form fields, fixed card heights
- Adjust responsive breakpoints to show sidebar on medium screens (768px+)
- Fix Chinese translation ambiguity for todo states
- Remove unnecessary divider between todo selector and manual input

BREAKING CHANGE: Removed PomodoroStats from timer layout (moved to sidebar)
Backend Improvements:
- Add force settlement mechanism to PomodoroManager to prevent data
  loss during phase transitions
- Force settlement flushes ImageConsumer buffers and processes all
  pending records before phase/session end
- Improves reliability of activity tracking by guaranteeing no
  captured actions are lost
- Add font size configuration support in SettingsManager
  (small, default, large, extra-large)

Frontend Enhancements:
- Extend ThemeProvider to support dynamic font size adjustment
  via CSS variables
- Update settings store with font size management
- Add font size selection in AppearanceSettings component
- Refine Pomodoro interface components with improved layouts
- Update UI components to support new font size system

UI/UX:
- Integrate font size controls in appearance settings
- Update sidebar and layout components for improved usability
- Add translations for new font size options in English
  and Chinese
- Enhance visual consistency across Pomodoro timer components

Technical:
- Process 354 additions across 20 files
- Maintain separation between user and system configuration
- Ensure backward compatibility with existing settings
- Improve data pipeline reliability during Pomodoro phase
  transitions
Introduces intelligent detection of coding environments (IDEs, terminals,
code editors) to apply more permissive filtering thresholds. This helps
capture small but meaningful changes during coding activities like cursor
movement and typing in dark-themed editors.

- Add CodingSceneDetector module with bundle ID, app name, and title
  pattern matching
- Integrate coding detection into ImageFilter and ImageAnalyzer
- Add configurable coding-specific thresholds in config.toml
  (0.92 similarity, lower contrast/activity)
- Adaptive threshold now considers coding scenes alongside
  static/video/normal types
- Fix font size setting not persisting across app restarts
  - Update get_font_size() and get_language() to read from database
  - Add fontSize field to SettingsInfoData response model
  - Load settings on app initialization
  - Update frontend store to handle fontSize from backend

- Fix pomodoro_work_phases table missing in existing databases
  - Add table creation to migration 0005
  - Create pomodoro_work_phases table with proper schema and indexes
  - Ensure UNIQUE constraint on session_id and phase_number

This ensures user preferences are properly stored in database and
pomodoro work phase tracking works correctly for all installations.
- Add global floating Pomodoro panel accessible from all pages
  - Create FloatingPomodoroTrigger: collapsible vertical tab on right edge
  - Create FloatingPomodoroPanel: 560px slide-in panel with full timer
  - Add PomodoroPanelStore for panel state management
  - Integrate with UIStore for panel open/close state

- Replace Pomodoro page timer with statistics dashboard
  - Create PomodoroStatsPanel with period selector (week/month/year)
  - Display 4 key metrics: total sessions, focus hours, daily average, completion rate
  - Show weekly focus chart with daily progress bars
  - Auto-refresh on session completion or deletion

- Add i18n translations for floating panel and stats
  - English: trigger labels, panel titles, placeholder text
  - Chinese: corresponding translations

- Mount floating components globally in App.tsx
- Keep Todo list on left side of Pomodoro page unchanged
…rd and todo list

- Add global floating timer panel for easy access during sessions
- Implement statistics dashboard with session overviews and detailed metrics
- Add PomodoroTodoList component for task tracking during sessions
- Introduce SessionDetailDialog for viewing session information
- Optimize static scene detection with adaptive accumulation settings
- Remove redundant PomodoroReview page
- Update i18n translations for English and Chinese
…clock

- Replace Web Speech API TTS with HTML5 Audio notification sounds
- Add 8-bit/16-bit style sound files for work/break/session completion
- Create desktop clock window with real-time countdown and progress ring
- Implement event-driven sync between main app and clock using phaseStartTime
- Add position persistence for clock window across restarts
- Update settings UI to support sound theme selection and preview
- Emit pomodoro-phase-switched event on session start for immediate clock sync
- Migrate voice settings to notification settings with backward compatibility
…ations

- Replace Framer Motion with Tailwind CSS for better performance
- Add custom animation utilities (page transitions, card hover, stagger)
- Implement JS hooks (useCounterAnimation, useSpringValue) with requestAnimationFrame
- Add stagger animations to lists, cards, and charts across all views
- Update pomodoro timer (larger font, remove duplicate task display)
- Add tab switching animations for Pomodoro and AITodos
- Automatic prefers-reduced-motion support via Tailwind
- Update CLAUDE.md with comprehensive animation guidelines
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants