Skip to content

Achievements Support and Pedram's List 11/29#8

Merged
pedramamini merged 41 commits intomainfrom
maestro-achievements
Dec 1, 2025
Merged

Achievements Support and Pedram's List 11/29#8
pedramamini merged 41 commits intomainfrom
maestro-achievements

Conversation

@pedramamini
Copy link
Collaborator

  • MAESTRO: Add confirmation dialog to clear system logs action
  • MAESTRO: Allow Cmd+Shift+F to switch to Files tab from Scratchpad
  • MAESTRO: Add Texas outline to About modal above 'Made in Austin, TX'
  • MAESTRO: Auto-hide TTS stop button when audio playback completes
  • MAESTRO: Add comma formatting to total cost in Claude session list stats panel
  • MAESTRO: Fix theme flash by waiting for settings before hiding splash
  • MAESTRO: Add inline image rendering for markdown preview in FilePreview
  • MAESTRO: Support Cmd+[] in addition to Cmd+Shift+[] for Git diff viewer tab navigation
  • MAESTRO: Improve Claude session details view with UUID display and number formatting
  • MAESTRO: Add Escape key support to close scratchpad image lightbox
  • MAESTRO: Fix Cmd+Shift+F not working in scratchpad editor mode
  • MAESTRO: Add LOCAL git hash version to local package builds
  • MAESTRO: Remove superfluous connected indicator from web interface header
  • MAESTRO: Add left/right arrow keys for collapsing/expanding groups in sidebar
  • MAESTRO: Add History help modal, human validation, and AutoRun pill improvements
  • MAESTRO: Add file path image support to Scratchpad preview
  • feat: UX improvements for tabs and /synopsis command
  • feat: UX improvements for thinking dropdown and toast notifications
  • fix: Add tabName and tabId to synopsis toast notifications
  • feat: Add pagination for Claude sessions list and session jump shortcuts
  • fix: Resolve web interface inputMode sync issue for commands
  • feat: Persist scroll position per AI tab and terminal view
  • feat: Show session name in history and fix cost display
  • feat: UI improvements and session jump shortcut fix
  • fix: Resolve web interface remote control connectivity issues
  • perf: Optimize keyboard input responsiveness and reduce CPU usage
  • fix: Connect OS notifications setting to toast system
  • feat: Add stop button to AutoRun thinking status pill
  • fix: Style TabBar scrollbar to match other panels
  • feat: Add conductor-themed achievement system for AutoRun tracking
  • feat: Update app icon and splash logo to conductor silhouette
  • fix: Restore wand glyph for web/PWA icons, refine elapsed time format
  • fix: Use proper conductor silhouette graphic for app icon and splash
  • fix: Resolve TDZ error in keyboard handler ref initialization
  • fix: Resolve TDZ error in keyboard handler ref initialization
  • fix: Enforce read-only mode by passing --permission-mode plan to Claude
  • feat: Add git branch copy button and improve toast layout
  • final tweaks in achievements

- Updated LogViewer to show ConfirmModal before clearing logs
- Modified ConfirmModal to auto-focus the Confirm button on mount
- Added focus ring styling to the Confirm button for better visibility
- User can now press Enter to confirm after clicking the clear logs button
Previously Cmd+Shift+F was explicitly blocked when the Scratchpad had focus,
preventing the global "Go to Files" shortcut from working. Now Cmd+Shift+F
propagates to the global handler while Cmd+F still opens search locally.
Added a simple SVG outline of Texas with a small dot marking Austin's
location, displayed above the "Made in Austin, TX" text in the About modal.
Add IPC event notification from main process to renderer when TTS
process finishes playing. The stop button now correctly disappears
when audio completes naturally, allowing users to replay.
The splash screen was being hidden after sessions loaded, but before
the theme settings were fully applied. This caused a visible flash
where the default Dracula theme appeared briefly before switching to
the user's actual saved theme.

Changes:
- Add settingsLoaded flag to useSettings hook that tracks when all
  async settings have been loaded from electron-store
- Add sessionsLoaded state in App.tsx to track session loading
- New useEffect waits for BOTH settingsLoaded and sessionsLoaded
  before calling window.__hideSplash()

Now the splash screen only fades out once the UI is completely
rendered with the correct theme, preventing any visual flash.
Added a custom MarkdownImage component that renders images inline within
markdown files. The component handles:
- Relative image paths (resolved relative to the markdown file's directory)
- Absolute file paths
- HTTP/HTTPS URLs
- Data URLs

Images are loaded via the existing fs:readFile IPC handler which returns
images as base64 data URLs. Includes loading and error states for better UX.
…mber formatting

- Show full UUID in header when no custom name; show UUID underneath custom name
- Round cost to 2 decimal places instead of 4
- Add formatNumber utility for k/M/B suffixes (handles millions/billions)
- Extend formatSize to include GB and TB support
- Move started timestamp to hover overlay on relative time
- Update all token counts to use proper scaling (k/M/B)
The image preview/lightbox component now properly handles the Escape key
to close, matching the expected behavior noted in the UI hint "(ESC to close)".
The scratchpad's container keydown handler was intercepting both Cmd+F and
Cmd+Shift+F, preventing the global 'Go to Files' shortcut from triggering.
Now only Cmd+F (without Shift) is intercepted for in-scratchpad search,
allowing Cmd+Shift+F to propagate to App.tsx's global handler.
Modified package.json to set VITE_APP_VERSION="LOCAL <8-char-git-hash>"
for all local packaging commands (package, package:mac, package:win,
package:linux). This makes it easy to identify local builds in the
About modal by showing version like "LOCAL 5345296" instead of the
package.json version.
…ader

Removed the green "Connected" badge from the upper right corner of the
mobile web header. Connection state is already clearly communicated via
the ConnectionStatusIndicator component which shows when disconnected
or reconnecting. Cleaned up related unused imports and interface props.
… sidebar

When keyboard focus is in the left bar sidebar:
- ArrowLeft collapses the current group or bookmarks section
- ArrowRight expands the current group or bookmarks section

This provides intuitive tree-style navigation in addition to the existing
Space key behavior for collapsing groups.
…mprovements

- Add History Help Widget with help modal (? icon in filter row)
- Add human validation feature for AUTO entries with double checkmark
- Add validated toggle in History details modal
- Add context window widget to History details view (calculates from usageStats)
- Make History details responsive (hide token In/Out on mobile)
- Remove external link jump button from History details (keep Resume only)
- Add AutoRun-specific thinking pill showing total elapsed time and task progress
- Pipe auto-run synopsis to TTS stack when audio feedback is configured
- Add history:update IPC handler for persisting validation state

Claude ID: 0d010118-90d3-40ec-a578-446e816de993
Maestro ID: 5a166b38-b7e9-47f0-a8ff-0113c65f2682
Extended the AttachmentImage component in Scratchpad to handle absolute
and relative file paths for images, not just maestro-attachment:// URLs.
Images referenced with file paths are now loaded via the fs:readFile IPC
handler, enabling consistent image rendering between FilePreview and
Scratchpad markdown previews.
- Auto-focus input when creating new tab with Command-T
- Scroll active tab into view when switching tabs (resume, toaster click, etc.)
- Show /synopsis command and response in tab message history
- Update /synopsis description to clarify it operates on active tab
- README: Update terminology from "sessions" to "agents" for consistency

Claude ID: 07bd3dc6-a279-4021-aa5b-adce71fd1815
Maestro ID: 5a166b38-b7e9-47f0-a8ff-0113c65f2682
- ThinkingStatusPill: Show tab names in dropdown instead of just UUID octets
  (Priority: namedSessions > tab name > UUID octet > session name)
- Toast notifications: Display session/tab name in accent-colored pill style
- Toast notifications: Click anywhere on toast to navigate to that session/tab
- Toast notifications: Clicking dismisses the toast after navigation
- Added sessionId and tabId to Toast interface for navigation support

Claude ID: 2be7b616-5e73-4e2d-a242-7108aef07792
Maestro ID: 5a166b38-b7e9-47f0-a8ff-0113c65f2682
Synopsis toast notifications were missing the session/tab pill because
tabName and tabId weren't being passed through. This fix ensures:
- synopsisData includes tabName and tabId from the completed tab
- Synopsis toast in App.tsx passes tabName and tabId
- /clear command synopsis toast also includes tab info

Claude ID: 2be7b616-5e73-4e2d-a242-7108aef07792
Maestro ID: 5a166b38-b7e9-47f0-a8ff-0113c65f2682
- Add paginated API (claude:listSessionsPaginated) for better performance with many sessions
- Load 100 sessions at a time, fetch more at 70% scroll
- Auto-load more sessions when filtered view has fewer than 50 visible
- Stats bar shows filtered or total count based on 'Show All' checkbox
- Add Opt+Cmd+NUMBER shortcut to jump to visible sessions (1-9, 0=10th)
- Show number badges on sessions when Opt+Cmd modifier held

Claude ID: 1cee4b61-1237-434a-bef1-8e5675c48639
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
The web interface was unable to send AI or terminal commands reliably
due to a race condition where the server's session state could be stale
compared to the web client's local state after mode switches.

Changes:
- Include inputMode in send_command messages from web client
- Update ExecuteCommandCallback type to accept optional inputMode
- Forward inputMode through IPC to renderer
- Renderer now uses web's intended inputMode instead of querying
  potentially stale session state
- Sync session state when web's mode differs from desktop

Also includes queue bypass logic for write commands when all
running/queued items are read-only (parallel execution optimization).

Claude ID: 6a6f610a-1001-4772-9bb7-63dc893320c3
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Add scroll position persistence so users can resume reading exactly where
they left off when switching between sessions, tabs, or restarting the app.

Changes:
- Add scrollTop field to AITab interface for per-tab scroll position
- Add terminalScrollTop field to Session for terminal mode scroll
- Add throttled (200ms) scroll save handler in TerminalOutput
- Restore scroll position on mount with requestAnimationFrame
- Wire up onScrollPositionChange callback through MainPanel to App

Also includes:
- Session jump shortcuts (Opt+Cmd+NUMBER) now work when modals open
- Session jump badges moved to left side of session item for visibility
- Bookmarked sessions included in session jump numbering
- Slash commands now queue through execution queue for consistency

Claude ID: 1cee4b61-1237-434a-bef1-8e5675c48639
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
- Add sessionName field to HistoryEntry type for better display
- History panel now shows session name instead of UUID when available
- Fix cost mismatch: use tab-level usageStats (matching UI header) instead
  of cumulative session-level stats
- Add getProjectStats IPC for aggregate stats across all sessions
- AgentSessionsBrowser now shows accurate totals with progressive loading

Claude ID: 906b25cb-32b7-46b7-896b-fd459f106720
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
- Fix Opt+Cmd+NUMBER shortcut to use e.code instead of e.key (macOS Option key produces special characters)
- Add Maestro session name to thinking pill dropdown for better identification
- Update About modal with Texas flag SVG
- Simplify aggregate stats display in AgentSessionsBrowser
- Enhance /synopsis command with structured summary and details parsing
- Document Jump to Agent shortcut in README.md

Claude ID: 1cee4b61-1237-434a-bef1-8e5675c48639
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
- Fix WebSocket connection being closed by React StrictMode double-mount
  by tracking connection and mount IDs to ignore stale events/cleanup
- Add tab sync with session selection: when selecting a session from web
  interface, desktop now also switches to the same active tab
- Update onRemoteSelectTab to also switch to the session if not active
- Clean up debug logging from troubleshooting

Claude ID: aba19eda-96f3-4309-96d8-931075d4ab52
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Major performance improvements to address keyboard input lag:

- InputArea: Add useMemo for command history and slash command filtering,
  use requestAnimationFrame for textarea auto-grow to prevent layout
  thrashing, wrap component in React.memo

- App.tsx: Refactor keyboard handler useEffect to use ref pattern instead
  of 51+ dependencies - listener now attaches once on mount instead of
  re-attaching on every state change

- SessionList: Optimize git polling - increase interval from 10s to 30s,
  pause polling when app is in background, resume on visibility change

- LogViewer: Optimize search filtering with lazy evaluation - check
  message/context before expensive JSON.stringify on log.data

- useTabCompletion: Add useCallback for getSuggestions, memoize shell
  history reference to maintain stable function identity

Claude ID: 33f0f964-5b7f-4240-9e40-8eddcecafe8e
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
The "Enable OS Notifications" setting existed in the UI but wasn't
actually wired up to trigger desktop notifications when toasts appeared.
The "Test Notification" button worked because it called the API directly,
but actual toast notifications (from task completions, etc.) never
triggered OS notifications.

Added setOsNotifications to ToastContext (mirroring the existing
setAudioFeedback pattern) and connected it in App.tsx so the setting
now properly controls whether toasts also show as OS notifications.

Claude ID: 3f3cd7e1-63cf-477b-8877-5f5b1b14c057
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Wire up onStopAutoRun callback through InputArea to ThinkingStatusPill,
allowing users to stop batch runs directly from the status indicator
without navigating to the Scratchpad panel.

Claude ID: dd9b53ae-9d92-44c8-a34e-3630f0d33aca
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Changed scrollbar-none to scrollbar-thin for consistency with other
scrollable areas in the application.

Claude ID: 7fc8be90-495b-4551-b389-295a95e6d81f
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Implement a gamification system that rewards users for cumulative AutoRun
usage with 11 conductor-themed badge levels (from "Apprentice Conductor"
to "Titan of the Baton").

Features:
- Achievement card in About modal showing current badge, progress, and stats
- Standing Ovation full-screen celebration overlay for badge unlocks
- Same celebration treatment for new personal longest-run records
- Trophy badge indicator in session list header (visible at level 1+)
- Expandable badge unlock history (visible at level 2+)
- Shareable achievement card (copy to clipboard or download as PNG)
- Theme-aware maestro conductor silhouette (light/dark variants)
- Badge data includes example conductors with Wikipedia links

Badge progression spans from 15 minutes to 10 years of cumulative
AutoRun time, with each badge featuring unique flavor text and
an example maestro from classical music history.

Claude ID: 97a10f0d-145d-4352-babd-6d9caed0f9dc
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Replace wand icon with conductor maestro silhouette for:
- App icon (icon.png, icon.icns, icon.ico)
- Startup splash screen
- PWA icons for web interface

The wand icon is preserved as icon-wand.png (the "glyph" version)
for use elsewhere in the UI where simplicity is preferred.
- Revert PWA icons back to wand glyph (favicon, mobile home screen)
- Update AutoRun elapsed time to human-readable format (e.g., 2h 10m 47s)

Icon usage clarified:
- Conductor silhouette: app icon + startup splash only
- Wand glyph: web interface, PWA icons, and other UI elements
Replace generated SVG conductor with the authentic conductor silhouette
graphic provided by the user. The conductor graphic now appears in:
- App icon (white silhouette on purple background)
- Startup splash screen
- Achievement overlays (dark/light variants for theme support)

Also includes a TabBar fix for initial scroll position of active tab.
Move keyboardHandlerRef.current assignment after all handler function
definitions to fix "Cannot access 'addNewSession' before initialization"
error. The useRef initial value was referencing const functions before
their declarations, causing a temporal dead zone violation on cold start.

Claude ID: 8a4a8b58-33e0-4d14-87df-262cdb3f4624
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
Achievement system polish:
- Remove separator line above "View on GitHub" in About modal
- Fix badge progression tooltip positioning (smart left/center/right)
- Make empty badge cells more visible (dashed border, higher opacity)
- Change tooltips to click-to-toggle (stays visible for Wikipedia links)
- Reorder tooltip content: Level X, Title, then description
- Add "Click a badge to view details" hint text

Developer Playground:
- Add playground() console command to open testing panel
- Create PlaygroundPanel component with achievements testing tab
- Quick-set badge levels 0-11 with single click
- Manual time sliders for cumulative time, longest run, total runs
- Standing Ovation trigger with badge level selection
- Preview AchievementCard with mock data in real-time
Read-only mode was purely cosmetic - it displayed the badge but never
actually told Claude to operate in plan-only mode. This allowed agents
to take destructive actions even when read-only was enabled.

Added --permission-mode plan to spawn arguments in two missing locations:
- processQueuedItem: checks item.readOnlyMode and targetTab.readOnlyMode
- Remote command handler: checks activeTab.readOnlyMode

Also includes minor UI improvements:
- Show tab name in session ID pill tooltip
- Move read-only badge from bottom-right to top-right of user messages

Claude ID: 83301ba2-5864-41f1-b6cf-eb68613c2ecb
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
- Add copy-to-clipboard button in git branch overlay with flash notification
- Move tab name to same line as group/project in toast notifications
  (wraps to second line only when space is insufficient)

Claude ID: 83301ba2-5864-41f1-b6cf-eb68613c2ecb
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
@claude
Copy link

claude bot commented Dec 1, 2025

Code Review: Maestro Achievements PR

Great work on this comprehensive feature update! This PR adds a conductor-themed achievement system and numerous UX improvements. Here's my detailed review:


Strengths

1. Well-Architected Achievement System

  • Clean separation of concerns with conductorBadges.ts for data/logic and useAchievements.ts for state management
  • The conductor theme is creative and well-researched with real historical examples
  • Proper TypeScript interfaces throughout (ConductorBadge, AchievementState, etc.)

2. Performance Improvements

  • Pagination implementation (lines 1626-1809 in src/main/index.ts) is excellent:
    • Cursor-based pagination avoids memory issues with large session lists
    • Only reads file content for the current page (not all sessions upfront)
    • Uses regex matching for fast token extraction instead of full JSON parsing
    • Batched processing with progressive updates (BATCH_SIZE = 20)
  • Good optimization strategy: stat files first, sort, then read only needed pages

3. Remote Control Fixes

  • The inputMode parameter fix for web interface (line 345, 360) addresses a real sync issue
  • Proper forwarding through IPC: Web to Main to Renderer ensures single source of truth
  • Added tabId support for session selection enables deep linking

4. Code Quality

  • Follows CLAUDE.md conventions (using standardized vernacular)
  • Consistent error handling with try-catch blocks and null checks
  • Good use of TypeScript strict mode
  • Proper React hooks patterns (useCallback, useEffect dependencies)

Concerns and Recommendations

1. Security - Package Scripts (Critical)

Location: package.json lines 25-28

Using shell command substitution in package.json scripts can be fragile:

  • Won't work on Windows unless using Git Bash/WSL
  • Could fail in CI environments without proper git context
  • No error handling if git command fails

Recommendation: Add a cross-platform Node.js script to generate version info, or use a package like cross-env for better cross-platform support with fallback logic.

2. Performance - Multiple Regex Passes

Location: src/main/index.ts lines 1706-1742

Calling content.matchAll() multiple times on the same large string. Consider combining regex passes or using stream-based parsing for better performance with hundreds of large session files.

3. Potential Bug - Cursor Position

Location: src/main/index.ts line 1683

If the cursor session is deleted/missing, it falls back to index 0, potentially showing duplicate sessions. Consider using a timestamp-based cursor instead of session ID for more robust pagination.

4. Missing Validation - History Entry Updates

Type definitions show validated field but unclear where validation logic exists. Should there be user permission checks before allowing validation updates?

5. Icon Generation Script

The HTML-based icon generator requires manual steps and canvas rendering may vary across browsers. Consider using a headless approach or Node.js canvas library for reproducibility.


Potential Bugs

1. Race Condition in Achievement Updates

If multiple AutoRun tasks complete simultaneously, there could be a race condition in updating cumulative stats. Ensure atomic updates or use a queue.

2. Missing Error Boundaries

New components like StandingOvationOverlay and AchievementCard should be wrapped in error boundaries to prevent crashes from breaking the entire app.

3. Memory Leak Risk - Project Stats

Location: src/main/index.ts lines 1812-1906

The batched stats calculation sends updates via IPC but doesn't check if the window is still interested. Add cancellation support or check if component is still mounted.


Minor Issues

  1. Magic Numbers: Consider extracting constants (line 1711: 20, line 1753: 10, line 1841: BATCH_SIZE = 20)
  2. Logging Verbosity: Logging every paginated request could be noisy in production
  3. Windows Compatibility: Package scripts use bash syntax that may not work on Windows without WSL/Git Bash

Test Coverage

No test files were modified. Recommend adding tests for:

  • Achievement badge progression logic
  • Pagination edge cases (empty list, single item, cursor at end)
  • Time formatting functions
  • Web interface remote control flow

Overall Assessment

Quality: 4/5 stars

This is a solid PR with creative features and meaningful performance improvements. The achievement system is well-designed, and the pagination implementation shows good understanding of performance optimization.

Main concerns:

  1. Cross-platform compatibility of package scripts (critical for Windows users)
  2. Security validation of history entry updates
  3. Potential memory issues with unbounded stats calculation

Recommendation: Approve with minor changes

Address the package.json scripts concern and consider the pagination cursor robustness. The rest can be addressed in follow-up PRs.

Great work overall! The conductor theme is delightful and the code quality is consistently high.

- Add scripts/set-version.mjs for cross-platform VITE_APP_VERSION setting
  (replaces bash-specific env var syntax that failed on Windows)
- Extract magic numbers into CLAUDE_SESSION_PARSE_LIMITS and CLAUDE_PRICING
  constants for better maintainability
- Remove legacy session format migration code - sessions now require aiTabs
- Fix session ID regex patterns to properly parse -ai-{tabId} format
- Remove deprecated aiLogs fallbacks - logs are exclusively in aiTabs now

Claude ID: bfd92ffb-a375-47be-94c5-fe4186325092
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
@claude
Copy link

claude bot commented Dec 1, 2025

Pull Request Review: Maestro Achievements System

This is a comprehensive PR with 5,648 additions and 1,071 deletions across 62 files, introducing an achievement system and numerous UX improvements. Here's my detailed review:


Strengths

1. Excellent Performance Optimizations 🚀

The Claude session parsing improvements are well-designed:

  • Regex-based token extraction (src/main/index.ts:1549-1563) is much faster than JSON parsing every line
  • Configurable scan limits via CLAUDE_SESSION_PARSE_LIMITS constants - smart abstraction
  • Pagination support with cursor-based navigation for large session lists (src/main/index.ts:1646)
  • Batched stats processing to prevent UI blocking

2. Security Best Practices 🔒

  • Proper use of execFileNoThrow for git operations in scripts/set-version.mjs:15
  • Note: scripts/set-version.mjs:45 uses shell: true, which is acceptable here since it's a development-only script wrapping npm commands, not handling user input

3. Well-Structured Achievement System 🏆

  • Clean separation of concerns: useAchievements.ts hook, conductorBadges.ts constants, AchievementCard.tsx UI
  • Thoughtful badge progression with real conductor references
  • Good use of TypeScript interfaces for type safety

4. Code Quality

  • Consistent error handling with try-catch blocks and null checking
  • Good use of React best practices (useCallback, useRef for stable references)
  • Proper layer stack integration for modals with correct priorities

⚠️ Issues & Recommendations

1. Critical: Shell Execution Security (scripts/set-version.mjs:43-46)

const child = spawn(command, commandArgs, {
  stdio: 'inherit',
  shell: true,  // ⚠️ Security concern
  env: { ...process.env, VITE_APP_VERSION: version }
});

Issue: Using shell: true enables command injection if command or commandArgs ever contain user input.

Recommendation: Remove shell: true unless absolutely necessary. Most commands (npm, electron-builder) work fine without shell interpretation:

const child = spawn(command, commandArgs, {
  stdio: 'inherit',
  // Remove shell: true
  env: { ...process.env, VITE_APP_VERSION: version }
});

If shell is truly needed for some commands, document WHY and consider using execFileSync instead for better control.

2. Potential Race Condition (src/renderer/App.tsx)

The keyboard handler initialization may have Temporal Dead Zone issues (mentioned in commit messages). Consider:

  • Ensuring refs are initialized before event listeners attach
  • Adding defensive null checks before accessing .current

3. Pricing Constants Hardcoded (src/main/index.ts:18-23)

const CLAUDE_PRICING = {
  INPUT_PER_MILLION: 3,
  OUTPUT_PER_MILLION: 15,
  // ...
};

Issue: API pricing changes will require code updates.

Recommendation: Consider moving to configuration or settings, or at least add a comment with the pricing model version and date (e.g., "Sonnet 4 pricing as of Dec 2024").

4. Missing Input Validation (src/main/index.ts:1650)

const { cursor, limit = 100 } = options || {};

Issue: limit could theoretically be set to a very large number, causing performance issues.

Recommendation: Add validation:

const limit = Math.min(Math.max(1, options?.limit || 100), 1000); // Cap at 1000

5. Error Handling Could Be More Specific

Multiple places use empty catch blocks (e.g., src/main/index.ts:1538, 1581). While acceptable for malformed JSON lines, consider logging at debug level for troubleshooting:

} catch (error) {
  // Skip malformed lines - expected in damaged session files
  logger.debug(`Skipping malformed line in session file`, 'ClaudeSessions');
}

6. Web Interface Input Mode Sync (src/main/index.ts:367, src/main/web-server.ts)

Good fix for passing inputMode through the callback! However, verify that the callback signature update is reflected in the TypeScript interface definition to prevent type mismatches.


🧪 Testing Recommendations

  1. Achievement System:

    • Test badge unlock at exact millisecond thresholds
    • Verify multiple rapid badge unlocks display correctly
    • Test with autoRunStats at edge values (0, very large numbers)
  2. Pagination:

    • Test with 0 sessions, 1 session, and 10,000+ sessions
    • Verify cursor behavior at boundaries (first page, last page)
    • Test with deleted/corrupted session files
  3. Web Interface:

    • Test inputMode sync with rapid command switching (AI ↔ terminal)
    • Verify session selection with tabId parameter
  4. Performance:

    • Benchmark Claude session loading with 1000+ large JSONL files
    • Monitor memory usage during stats calculation

📝 Minor Suggestions

  1. Documentation: Add JSDoc comments to the new claude:listSessionsPaginated IPC handler explaining the pagination strategy
  2. Magic Numbers: FIRST_MESSAGE_PREVIEW_LENGTH: 200 is used in multiple places - good that it's a constant!
  3. Type Safety: Consider using as const for CONDUCTOR_BADGES array to improve TypeScript inference
  4. Accessibility: The StandingOvationOverlay has good ARIA labels - nice work!

🎯 Summary

This is a high-quality PR with thoughtful architecture and solid execution. The achievement system is fun and well-implemented, and the performance optimizations show good understanding of bottlenecks.

Main action items:

  1. Remove shell: true from scripts/set-version.mjs unless absolutely necessary (security)
  2. 📊 Add validation for pagination limit parameter (robustness)
  3. 📝 Consider externalizing pricing constants (maintainability)

Recommendation: ✅ Approve with minor changes - address the shell security concern and pagination validation, then this is ready to merge.

Great work on this feature-rich update! 🎉

- Remove localStorage to electron-store migration for sessions/groups
- Remove enterToSend to enterToSendAI/enterToSendTerminal migration
- Simplify history filtering to only match exact sessionId (no legacy fallback)

Claude ID: 33f0f964-5b7f-4240-9e40-8eddcecafe8e
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
@claude
Copy link

claude bot commented Dec 1, 2025

Comprehensive Code Review: PR #8 - UX Improvements, Performance Optimizations, and Achievement System

Executive Summary

This is a substantial PR with 37+ commits, 5,655 additions, and changes to 65 files. The changes include major performance optimizations, bug fixes, a new achievement system, and numerous UX improvements. Overall, the code quality is very high, with excellent adherence to project conventions and thoughtful implementation. However, there are a few areas that warrant attention before merging.


1. Code Quality & Best Practices ✅ Excellent

Strengths

TypeScript Conventions

  • All new interfaces properly defined (AchievementState, PendingAchievement, AutoRunStats, etc.)
  • Types exported correctly through preload.ts for IPC safety
  • Strict mode compliance maintained throughout

React Best Practices

  • Proper use of React.memo in InputArea
  • Excellent use of useMemo and useCallback for performance
  • Pure helper functions moved outside components to prevent recreation

Project Convention Adherence

  • Consistent use of standardized vernacular (AI Terminal, Command Terminal, Left Bar, Right Bar)
  • Inline styles for theme colors, Tailwind for layout ✅
  • Proper modal registration with LayerStackContext and priorities
  • Settings persistence following the documented pattern

Minor Issues

⚠️ Issue 1: Inconsistent Comment Style - Some multi-line comments use single / instead of //


2. Potential Bugs or Issues ⚠️ Needs Attention

Critical Issues

🔴 CRITICAL: TDZ Fix May Be Incomplete (src/renderer/App.tsx)

The PR attempts to fix a Temporal Dead Zone error by moving keyboardHandlerRef.current assignment after function definitions. However, if a keyboard event fires during initial render before the assignment executes, ctx will be null.

Recommendation: Add a null check in the event handler:

const ctx = keyboardHandlerRef.current;
if (!ctx) return; // Guard against initial render race

🟡 Issue 2: WebSocket Connection Race Condition (src/renderer/hooks/useWebSocket.ts)

The fix for StrictMode using connectionIdRef and mountIdRef is clever, but WebSocket message handlers don't validate connection ID like event handlers do.

Recommendation: Add connection ID validation to the handleMessage callback.

🟡 Issue 3: Missing Error Handling in Achievement Canvas Generation (StandingOvationOverlay.tsx)

The ctx.roundRect() calls may not be supported in older browsers.

Recommendation: Add feature detection or try-catch fallback.

Minor Issues

⚠️ Issue 4: Scroll Throttling Timer Not Cleaned Up Properly (TerminalOutput.tsx) - The cleanup only happens on unmount, not when dependencies change.

⚠️ Issue 5: Git Polling Continues After Session Deletion (SessionList.tsx) - Doesn't check session existence before processing results.


3. Performance Considerations ✅ Excellent

Major Wins ⭐

Keyboard Handler Ref Pattern - The refactor to use a ref instead of 51+ dependencies is brilliant! Prevents keyboard listener from being re-attached on every state change. Estimated improvement: Eliminates 100+ event listener operations per second.

Git Polling Optimization - Increased interval from 10s to 30s, pauses when app is in background. CPU usage reduction: ~66% for git operations.

RequestAnimationFrame for Layout Operations - InputArea auto-grow and scroll restoration use RAF to prevent layout thrashing. Textbook performance optimization.

LogViewer Search Optimization - Lazy evaluation checks message/context before expensive JSON.stringify(log.data). Estimated improvement: 10-100x faster.

Minor Concerns

⚠️ Issue 6: Claude Session Pagination May Load Too Much - Default 100 sessions could load 100MB+ into memory.

⚠️ Issue 7: Achievement Badge Tooltip Positioning - Recalculates styles on every render, could be memoized.


4. Security Concerns ✅ Good / ⚠️ Minor Issues

Strengths

Proper Use of execFileNoThrow ✅ - All git operations use safe command execution, preventing shell injection.

WebSocket Security ✅ - Security token (UUID) required for all web interface access.

IPC Handler Security ✅ - New handlers follow established patterns with proper validation.

Read-Only Mode ✅ - The --permission-mode plan flag properly enforces read-only mode.

Minor Concerns

⚠️ Issue 8: Web Interface inputMode Sync - No validation that web client's mode matches actual Claude session state. Could lead to commands sent to wrong process.

Recommendation: Add mode validation and auto-sync.

⚠️ Issue 9: Canvas-Based Image Sharing - Verify no sensitive data (project paths, session IDs) leaks in achievement canvas.


5. Architecture & Design ✅ Excellent

Achievement System Design ⭐ Outstanding

Well-Structured - Clean separation with useAchievements hook, proper state management, no prop drilling.

Proper Integration - Minimal coupling, uses existing LayerStackContext, themed conductor metaphor is delightful.

Pagination Design ⭐ Good

Cursor-based pagination prevents skipping/duplicates. Efficient two-pass approach (stats first, then content).

Scroll Persistence ⭐ Excellent

Per-tab tracking with throttled saves, RAF restoration, robust reset handling.

Web Interface Sync Fix ⭐ Solid

Correctly identified race condition and passed clientInputMode explicitly as single source of truth.


6. Testing Recommendations

Critical Path Testing

  1. Verify keyboard shortcuts work on cold start before ref assignment
  2. Test rapid mode switching from web UI while desktop is busy
  3. Trigger achievement badge unlocks at boundaries
  4. Test rapid tab switching with large log histories
  5. Load 1000+ Claude sessions and verify no memory leaks

Edge Cases

  • WebSocket reconnection during StrictMode cycles
  • Git polling when sessions deleted mid-poll
  • Canvas generation in Safari
  • Scroll restoration when logs cleared while scrolled up

Summary & Recommendations

Must Fix Before Merge 🔴

  1. Add null check in keyboard handler (App.tsx)
  2. Add connection ID validation to WebSocket message handler
  3. Add feature detection for ctx.roundRect() in canvas generation

Should Fix 🟡

  1. Fix scroll throttling cleanup in TerminalOutput
  2. Add abort signal for git polling in SessionList
  3. Add mode validation in web interface inputMode sync
  4. Standardize comment style

Nice to Have 🟢

  1. Consider reducing default pagination size (100 → 50)
  2. Memoize badge tooltip positioning
  3. Add sortBy parameter to pagination API

Celebrate 🎉

  • Outstanding performance work - keyboard handler ref pattern, git polling optimizations, RAF usage
  • Excellent security hygiene - consistent use of execFileNoThrow, proper token validation
  • Delightful UX additions - achievement system, scroll persistence, pagination
  • Solid architecture - clean separation of concerns, minimal coupling
  • High code quality - TypeScript discipline, React best practices

Verdict

APPROVE with minor fixes

This is an exemplary PR that demonstrates deep understanding of React performance, security best practices, and maintainable architecture. The issues identified are minor and easily addressed. The achievement system is a delightful addition that will enhance user engagement. Once the 3 critical issues are resolved, this PR will be a significant improvement to the codebase.

Estimated Risk: Low
Estimated Value: Very High
Code Quality: 9/10


Review completed with analysis of 65 changed files across main process, renderer, and web interface.

- Fix AI input lag by using local state for typing, syncing to session
  state only on blur/submit instead of every keystroke
- Add esbuild.drop to strip console.* and debugger in production builds
- Memoize handleInputFocus and handleSessionClick callbacks in MainPanel
- Simplify textarea auto-grow by removing unnecessary RAF scheduling
- Fix AgentSessionsBrowser by changing button to div (nested button issue)
- Restore legacy history filter fallback for entries without sessionId

Claude ID: 33f0f964-5b7f-4240-9e40-8eddcecafe8e
Maestro ID: b9bc0d08-5be2-4fdf-93cd-5618a8d53b35
@claude
Copy link

claude bot commented Dec 1, 2025

Pull Request Review

This is a comprehensive PR with 37 commits and 5,698 additions that brings substantial UX improvements, performance optimizations, and new features to Maestro. Overall, the code quality is high and aligns well with the project's conventions outlined in CLAUDE.md. Here's my detailed feedback:


Strengths

1. Code Quality & Architecture

  • Excellent adherence to CLAUDE.md conventions: Uses proper terminology ("Left Bar", "Right Bar", "Main Window"), follows commit message format, and uses inline styles for theme colors
  • Well-structured constants: The addition of CLAUDE_SESSION_PARSE_LIMITS and CLAUDE_PRICING constants in src/main/index.ts is excellent for maintainability
  • Good separation of concerns: Pagination logic properly separated into new IPC handlers
  • TypeScript safety: Proper type guards and nullable handling throughout (e.g., filter((s): s is NonNullable<typeof s> => s !== null))

2. Performance Optimizations

The performance improvements are well-thought-out and necessary:

  • React.memo and useMemo usage in InputArea to prevent unnecessary re-renders
  • RequestAnimationFrame for textarea auto-grow to prevent layout thrashing
  • Ref pattern for keyboard handlers - excellent fix moving from 51+ dependencies to a stable ref
  • Git polling optimization - 10s → 30s interval with pause on background
  • Pagination for Claude sessions - cursor-based pagination prevents loading all sessions at once
  • Lazy search filtering in LogViewer with early bailout before expensive JSON.stringify

3. User Experience Enhancements

  • Scroll position persistence per tab is a great quality-of-life improvement
  • Session jump shortcuts (Opt+Cmd+NUMBER) with visual badges
  • Achievement system adds delightful gamification
  • Confirmation dialogs for destructive actions (clearing logs)
  • AutoRun improvements with stop button and progress tracking

⚠️ Issues & Concerns

1. Security Concerns

Critical: Command Injection Risk in set-version.mjs

const child = spawn(command, commandArgs, {
  stdio: 'inherit',
  shell: true,  // ⚠️ SECURITY RISK
  env: { ...process.env, VITE_APP_VERSION: version }
});

Problem: Using shell: true with user-controlled input creates a command injection vulnerability. While this script is only used for local builds, it violates the security principle in CLAUDE.md:

Always use execFileNoThrow for external commands... Never use shell-based command execution

Recommendation: Remove shell: true since you're already using the safe array-based arguments pattern. The shell isn't needed here.

const child = spawn(command, commandArgs, {
  stdio: 'inherit',
  // shell: true,  // Remove this line
  env: { ...process.env, VITE_APP_VERSION: version }
});

Git Hash Validation

The getGitHash() function properly uses execFileSync with array args (✅), but doesn't validate the output format:

function getGitHash() {
  try {
    const hash = execFileSync('git', ['rev-parse', '--short=8', 'HEAD'], {
      encoding: 'utf8',
      stdio: ['pipe', 'pipe', 'pipe']
    }).trim();
    return hash;  // Should validate format: /^[0-9a-f]{8}$/
  } catch {
    return 'unknown';
  }
}

2. Potential Bugs

Race Condition in Web Interface Mode Sync

// src/main/index.ts line ~367
server.setExecuteCommandCallback(async (sessionId: string, command: string, inputMode?: 'ai' | 'terminal') => {
  // ...
  mainWindow.webContents.send('remote:executeCommand', sessionId, command, inputMode);

While the PR addresses inputMode sync issues, there's still potential for race conditions if:

  • Multiple web clients send commands simultaneously
  • Desktop and web both modify session state at the same time

Recommendation: Consider adding a sequence number or timestamp to commands for proper ordering.

Unbounded Memory Growth in Pagination

// src/main/index.ts line ~1673
const fileStats = await Promise.all(
  sessionFiles.map(async (filename) => {
    // Loads ALL file stats into memory before pagination

If a user has thousands of sessions, this loads all stats into memory before slicing. Consider streaming or batch processing.

Missing Error Boundary for Achievement Overlay

The new "Standing Ovation" celebration overlay could crash the entire UI if rendering fails. Consider wrapping it in an error boundary.

3. Code Quality Issues

Duplicate Code in Pagination

The claude:listSessionsPaginated handler has ~150 lines of duplicated logic from claude:listSessions. Consider extracting shared parsing logic:

function parseClaudeSession(filePath: string, content: string, stats: Stats): ClaudeSessionMetadata {
  // Shared parsing logic
}

Magic Numbers

// What does 70% represent? Why 50?
// Auto-load more sessions when filtered view has fewer than 50 visible
if (filteredSessions.length < 50) { ... }

Add constants with descriptive names.

Inconsistent Error Handling

// Sometimes returns null
return null;

// Sometimes returns empty array  
return { sessions: [], hasMore: false, totalCount: 0, nextCursor: null };

Standardize error responses across similar handlers.

4. Performance Considerations

Regex Performance on Large Files

const userMessageCount = (content.match(/"type"\s*:\s*"user"/g) || []).length;

For very large session files (100MB+), regex on entire content could be slow. Consider:

  • Streaming line-by-line for token counting
  • Caching parsed results with file hash

Git Polling Still Heavy

While increased to 30s, git polling still runs for ALL sessions. Consider:

  • Only poll visible sessions
  • Use file system watchers instead of polling

📝 Test Coverage Needs

This PR lacks automated tests for critical functionality:

High Priority

  1. Pagination logic - cursor handling, boundary cases (empty list, single item, etc.)
  2. Command execution with inputMode - ensure sync works correctly
  3. Scroll position persistence - save/restore logic
  4. Achievement system - badge progression, unlock triggers

Medium Priority

  1. Session jump shortcuts - keyboard handling
  2. Performance optimizations - verify no regressions in re-render counts
  3. Regex-based parsing - validate token extraction accuracy

Recommendation

Add at least unit tests for the pagination handler and integration tests for web interface command sync.


🎯 Minor Issues

  1. Missing JSDoc comments on new public IPC handlers (claude:listSessionsPaginated, claude:getProjectStats)
  2. Console exposure - window.playground could be removed in production builds
  3. Hardcoded pricing - consider making CLAUDE_PRICING configurable for when API pricing changes
  4. Icon file size - build/icon.png changed from 7KB to potentially larger - verify final size
  5. Package.json script complexity - nested node scripts/set-version.mjs npm run build could fail silently

🎨 Positive Highlights

  1. Achievement system is delightful - great gamification with conductor theme
  2. Scroll persistence - addresses a real UX pain point
  3. Performance fixes - the keyboard input lag fix is crucial
  4. Web interface improvements - better sync and connectivity handling
  5. Consistent branding - conductor silhouette ties everything together nicely

📊 Summary

Category Rating Notes
Code Quality ⭐⭐⭐⭐☆ Clean, well-structured, follows conventions
Security ⚠️ Command injection risk in set-version.mjs
Performance ⭐⭐⭐⭐⭐ Excellent optimizations throughout
Bug Risk ⚠️ Race conditions, memory concerns
Test Coverage ⚠️ Missing critical tests
UX Impact ⭐⭐⭐⭐⭐ Significant improvements

Recommendations

Before Merge

  1. ✅ Fix shell: true in set-version.mjs
  2. ✅ Add git hash format validation
  3. ✅ Extract duplicate session parsing logic
  4. ✅ Add JSDoc to new IPC handlers

Follow-up PRs

  1. Add test coverage for pagination and web sync
  2. Implement error boundary for achievement overlay
  3. Optimize git polling with file system watchers
  4. Add streaming for very large session files

Great work overall! The performance improvements alone make this a valuable PR. Just address the security concern in set-version.mjs before merging. 🚀

@pedramamini pedramamini changed the title maestro achievements Achievements Support and Pedram's List 11/29 Dec 1, 2025
@pedramamini pedramamini merged commit 6689f68 into main Dec 1, 2025
1 check passed
@pedramamini pedramamini deleted the maestro-achievements branch December 1, 2025 15:40
@claude claude bot mentioned this pull request Dec 6, 2025
@claude claude bot mentioned this pull request Dec 19, 2025
needmorecowbell added a commit to needmorecowbell/Maestro that referenced this pull request Feb 19, 2026
Analyze event subscriptions, tool-execution data model per agent,
risky operation detection patterns, and storage requirements.
Rating: Moderate — all event APIs exist but needs plugin-scoped
storage API (Gap RunMaestro#8) and main-process component for SQLite.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
needmorecowbell added a commit to needmorecowbell/Maestro that referenced this pull request Feb 19, 2026
Analyze event subscriptions, tool-execution data model per agent,
risky operation detection patterns, and storage requirements.
Rating: Moderate — all event APIs exist but needs plugin-scoped
storage API (Gap RunMaestro#8) and main-process component for SQLite.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
needmorecowbell added a commit to needmorecowbell/Maestro that referenced this pull request Feb 19, 2026
Analyze event subscriptions, tool-execution data model per agent,
risky operation detection patterns, and storage requirements.
Rating: Moderate — all event APIs exist but needs plugin-scoped
storage API (Gap RunMaestro#8) and main-process component for SQLite.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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.

1 participant

Comments