-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
feat(ui): implement usage statistics badge for top bar (ACS-228) #975
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(ui): implement usage statistics badge for top bar (ACS-228) #975
Conversation
…ndyMik90#311) * fix(python): use venv Python for all services to fix dotenv errors Services were spawning Python processes using findPythonCommand() which returns the bundled Python directly. However, dependencies like python-dotenv are only installed in the venv created from the bundled Python. Changes: - Add getConfiguredPythonPath() helper that returns venv Python when ready - Update all services to use venv Python instead of bundled Python directly: - memory-service.ts - memory-handlers.ts - agent-process.ts - changelog-service.ts - title-generator.ts - insights/config.ts - project-context-handlers.ts - worktree-handlers.ts - Fix availability checks to use findPythonCommand() (can return null) - Add python:verify script for bundling verification The flow now works correctly: 1. App starts → findPythonCommand() finds bundled Python 2. pythonEnvManager creates venv using bundled Python 3. pip installs dependencies (dotenv, claude-agent-sdk, etc.) 4. All services use venv Python → has all dependencies 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]> * fix lintin and test --------- Co-authored-by: Claude <[email protected]>
…Mik90#313) Fixes the beta auto-update bug where the app was offering downgrades (e.g., showing v2.7.1 as "new version available" when on v2.7.2-beta.6). Changes: - version-manager.ts: New parseVersion() function that separates base version from pre-release suffix. Updated compareVersions() to handle pre-release versions correctly (alpha < beta < rc < stable). - app-updater.ts: Import and use compareVersions() for proper version comparison instead of simple string inequality. - Added comprehensive unit tests for version comparison logic. Pre-release ordering: - 2.7.1 < 2.7.2-alpha.1 < 2.7.2-beta.1 < 2.7.2-rc.1 < 2.7.2 (stable) - 2.7.2-beta.6 < 2.7.2-beta.7
…ik90#246) (AndyMik90#318) Correctly validate persisted task status against calculated status. Previously, if a task was 'in_progress' but had no active subtasks (e.g. still in planning or between phases), the calculated status 'backlog' would override the stored status, causing the UI to revert to 'Start'. This fix adds 'in_progress' to the list of active process statuses and explicitly allows 'in_progress' status to persist when the underlying plan status is also 'in_progress'.
…yMik90#317) Combined PR with: 1. Alex's version auto-update changes from PR AndyMik90#316 2. Auto-updater manifest file generation fix Changes: - Add --publish never to package scripts to generate .yml manifests - Update all build jobs to upload .yml files as artifacts - Update release step to include .yml files in GitHub release - Auto-bump version in package.json files before tagging This enables the in-app auto-updater to work properly by ensuring latest-mac.yml, latest-linux.yml, and latest.yml are published with each release. Co-authored-by: Alex <[email protected]>
…set (AndyMik90#243) (AndyMik90#323) Co-authored-by: Black Circle Sentinel <[email protected]>
AndyMik90#337) This commit optimizes the merge handler to prevent UI blocking by converting synchronous file operations to asynchronous I/O: - Make handleProcessExit async to support async operations - Replace readFileSync with fsPromises.readFile for commit message reading - Refactor plan persistence to use async I/O with parallel updates via Promise.all() - Implement fire-and-forget pattern for plan updates to prevent blocking the response - Improve error handling with separate tracking for main vs worktree plans These changes eliminate blocking I/O operations that could freeze the UI during merge operations, particularly when updating implementation plans across both the main project and worktree. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Sonnet 4.5 <[email protected]>
…AndyMik90#343) The old ProjectSettings modal has been replaced by the unified AppSettings dialog. This removes: - `ProjectSettings.tsx` - deprecated modal component - `project-settings/ProjectSettings.tsx` - unused refactored version - `hooks/useProjectSettings.ts` - replaced by project-settings/hooks/ - `hooks/useEnvironmentConfig.ts` - only used by deprecated modal - `hooks/useClaudeAuth.ts` - only used by deprecated modal - `hooks/useLinearConnection.ts` - only used by deprecated modal - `hooks/useGitHubConnection.ts` - only used by deprecated modal - `hooks/useInfrastructureStatus.ts` - only used by deprecated modal Updated index files to remove deprecated exports.
* fix(execution): add structured phase event emission and improve phase transition handling - Add emit_phase() calls in coder.py for PLANNING, CODING, COMPLETE, and FAILED phases - Add emit_phase() calls in planner.py for follow-up planning phase - Add emit_phase() calls in qa/loop.py for QA_REVIEW, QA_FIXING, COMPLETE, and FAILED phases - Add parsePhaseEvent() to agent-events.ts to prioritize structured events over log parsing - Default to 'planning' phase in PhaseProgressIndicator when running but phase * fix(execution): prevent premature 'complete' phase during QA workflow - Remove COMPLETE phase emission from coder.py when subtasks finish (QA hasn't run yet) - Add phase regression prevention in agent-events.ts to block fallback text matching from moving backwards (e.g., QA → coding) - Remove 'complete' phase detection from "BUILD COMPLETE" banner text (only structured emit_phase(COMPLETE) from QA approval should set complete) - Add line buffering in agent-process.ts to prevent split __EXEC_PHASE * fix(execution): prevent phase regression and improve JSON parsing robustness - Add phase regression check to 'planning' phase detection in agent-events.ts - Prevent 'failed' phase from overwriting 'complete' or 'failed' from structured events in agent-process.ts - Add extractJsonObject() to handle JSON with trailing garbage in phase-event-parser.ts - Implements brace-matching parser that handles escaped quotes and nested objects - Prevents parse failures when __EXEC_PHASE__ JSON is followed by log * refactor: improve variable naming clarity in phase event parsing - Rename 'escape' to 'isEscaped' in extractJsonObject() for better readability - Rename list comprehension variable 'l' to 'line' in test_phase_event.py * feat(agent-events): add Zod validation and refactor phase event parsing - Add zod dependency (^4.2.1) for runtime type validation - Refactor phase event parsing into specialized parser classes: - ExecutionPhaseParser for task execution phases - IdeationPhaseParser for ideation workflow phases - RoadmapPhaseParser for roadmap generation phases - Add strict Zod schemas for phase event validation: - Reject invalid message types (must be string) - Reject invalid progress values (must be 0-100 * refactor(agent-events): remove parser delegation and inline phase detection logic - Remove ExecutionPhaseParser, IdeationPhaseParser, and RoadmapPhaseParser delegation - Inline all phase detection logic directly into AgentEvents methods - Add wouldPhaseRegress() check to prevent fallback text matching from moving backwards - Add parsePhaseEvent() call to prioritize structured __EXEC_PHASE__ events - Add checkRegression() helper to validate phase transitions before applying fallback matches - Filter * test(subprocess): update test expectations to include newlines in buffered output - Update subprocess-spawn.test.ts to append '\n' to test data and expectations - Reflects line buffering behavior where output is processed line-by-line - Skip ipc-handlers.test.ts exit event test (status change logic removed) - Remove exit code 0 test case that no longer applies after status change removal * refactor(ideation-phase-parser): add terminal state guard and extract progress calculation - Add terminal state check to prevent phase changes after completion - Extract calculateGeneratingProgress() helper with division-by-zero protection - Return 90% progress fallback when totalTypes is 0 or negative - Apply helper to both progress calculation paths (no phase change and phase detected) * fix(phase-parser): prevent premature QA phase detection during planning Add canEnterQAPhase guard to fallback text matching in agent-events.ts and execution-phase-parser.ts. QA phases can now only be triggered via text matching if currentPhase is already 'coding', 'qa_review', or 'qa_fixing'. This prevents tasks from jumping to QA Review column when planning phase output contains QA-related text. Structured events from backend (__EXEC_PHASE__:...) bypass this check. * fix(task-store): prevent stale plan data from overriding status during active execution When a task is restarted, the file watcher immediately reads the existing implementation_plan.json and calls updateTaskFromPlan. If the old plan has all subtasks completed, it would set status to 'ai_review' before the agent process emits the 'planning' phase event. This fix checks if the task is in an active execution phase (planning, coding, qa_review, qa_fixing) and if so, does NOT let the plan data override the status. The execution phase takes precedence. Added 4 tests to verify the behavior. * Reorder imports in coder.py for clarity Moved the import of ExecutionPhase and emit_phase from phase_event to follow the project's import organization conventions and improve code readability. * fix: address PR review comments from CodeRabbit - Clamp progress values to 0-100 range in phase_event.py - Remove unused PhaseEvent import in test file - Simplify terminal phase check in ideation-phase-parser.ts - Add regression prevention in roadmap-phase-parser.ts - Use z.infer for PhaseEvent type derivation * fix: add type assertions for Zod-validated phase values TypeScript couldn't infer the literal type from Zod enum validation. Added explicit type assertions since the phase is already validated. * fix: correct misleading test name for QA loop transition The test was named 'should not regress' but actually verified that qa_fixing → qa_review IS allowed (valid re-review after fix). Renamed to clarify the expected behavior. * fix: define phase variable from rawPhase in PhaseProgressIndicator The prop was renamed during destructuring but the derived variable was never defined, causing 'phase is not defined' runtime error. * fix(security): add Python path validation to prevent command injection Add validatePythonPath() function that validates user-configurable Python paths before use in spawn(). This prevents potential command injection attacks via malicious paths. Security checks implemented: - Block shell metacharacters (;|&<> etc.) - Validate against allowlist of known Python locations - Verify file exists and is executable - Confirm it's actually Python via --version Applied validation to all affected locations: - AgentProcessManager.configure() - InsightsConfig.configure() - ChangelogService.configure() - TitleGenerator.configure() Addresses: PR AndyMik90#249 review - CRITICAL security finding * fix: add sequence tracking to prevent race conditions in state updates Add sequenceNumber field to ExecutionProgress to track update order and prevent stale updates from overwriting newer state. Changes: - Add sequenceNumber to ExecutionProgress interface - updateExecutionProgress now rejects updates with lower sequence numbers - All execution-progress emissions now include monotonically increasing sequence numbers This prevents race conditions where out-of-order updates could cause incorrect task state display. Addresses: PR AndyMik90#249 review - HIGH severity race condition finding * refactor: extract helper methods from spawnProcess() to reduce complexity Break down the 294-line spawnProcess() into smaller focused methods: - setupProcessEnvironment(): Creates the process environment object - handleProcessFailure(): Orchestrates rate limit and auth failure handling - handleRateLimitWithAutoSwap(): Handles auto-swap logic for rate limits - handleAuthFailure(): Detects and handles authentication failures The main spawnProcess() is now significantly cleaner with single-responsibility helper methods that are easier to test and maintain. Addresses: PR AndyMik90#249 review - HIGH severity complexity finding * fix: improve phase handling with type guards and better error reporting - Add type guard validation in checkRegression() before calling wouldPhaseRegress() to prevent undefined lookups in PHASE_ORDER_INDEX - Add warning log when calculateOverallProgress() receives unknown phase instead of silently returning 0% - Change 'failed' phase index from 5 to 99 to clearly indicate it's outside normal progression (like 'idle' uses -1) These changes improve defensive programming and debugging capabilities for phase state management. Addresses: PR AndyMik90#249 review - MEDIUM severity findings * refactor(security): consolidate Python path validation logic into reusable helper Extract repeated validation pattern into getValidatedPythonPath() helper to reduce code duplication across services. Changes: - Add getValidatedPythonPath() helper that encapsulates validation logic - Replace duplicated validation blocks in ChangelogService, InsightsConfig, and TitleGenerator with helper call - Improve isSafePythonCommand() to normalize whitespace before checking - Add newline/carriage return to DANGEROUS_SHELL_CHARS regex * fix(tests): enable exit event forwarding test - Remove it.skip from 'should forward exit events with status change on failure' - Add proper test setup: create project and task before emitting exit event - Add mock for notificationService to prevent errors during test * fix(security): use mkdtempSync for secure temp directory in tests Addresses CodeQL 'Insecure temporary file' warning by using mkdtempSync with a random suffix instead of a predictable path. --------- Co-authored-by: Andy <[email protected]> Co-authored-by: Alex <[email protected]>
…dyMik90#344) Remove the backwards compatibility re-export file `TaskDetailPanel.tsx` that was only re-exporting from `./task-detail/`. This file was unused - the app imports directly from `./task-detail/TaskDetailModal`. Removed: - `src/renderer/components/TaskDetailPanel.tsx` - unused re-export file - Export from `index.ts`
* feat: centralize CLI tool path management Created centralized CLI tool manager with multi-level detection priority (user config → venv → Homebrew → system PATH). Key changes: - New cli-tool-manager.ts with platform-aware detection (macOS Apple Silicon/Intel, Windows, Linux) - Migrated 75 hardcoded CLI tool usages across 12 files (Python, Git, GitHub CLI) - Added Settings UI for user configuration with auto-detection display showing detected path, version, and source - Implemented version validation (Python 3.10+ required) - Session-based caching without TTL expiration - Full i18n support (EN/FR) for new Settings UI elements This eliminates hardcoded tool paths and provides consistent, configurable CLI tool management across the application. * fix(lint): resolve linting issues in CLI tool manager - Remove unused getAugmentedEnv import - Replace console.log with console.warn for logging - Fix template string syntax error in release-service.ts (backtick vs quote) Reduces lint errors from 185 to 179 (0 errors, 179 warnings) * fix(security): address CodeRabbit review feedback - Fix command injection vulnerability in validateGitHubCLI using execFileSync - Remove redundant execSync calls in release-service.ts - Fix Electron context separation by moving ToolDetectionResult to shared types - Add loading state to Settings UI to prevent flashing 'Not detected' - Improve error handling with safe string conversion Addresses security and code quality issues identified by automated review. * fix(security): fix all command injection vulnerabilities in CLI tool usage Replace all execSync calls using getToolPath() with execFileSync to prevent command injection attacks. This fixes CodeQL security warnings about unsanitized environment variables in command execution. Changes: - settings-handlers.ts: 1 fix (git init) - release-service.ts: 20 fixes (git/gh commands in release flow) - worktree-handlers.ts: 22 fixes (git worktree operations) - project-handlers.ts: 3 fixes (git branch operations) - github/utils.ts: 1 fix (gh auth token) - github/oauth-handlers.ts: 11 fixes (gh API and git remote operations) - github/release-handlers.ts: 3 fixes (gh auth, git describe, git log) - changelog/git-integration.ts: 6 fixes (git branch and tag operations) Total: 67 command injection vulnerabilities fixed Security Impact: - Prevents malicious users from injecting arbitrary commands via CLI tool paths - Uses execFileSync which executes binaries directly without shell interpolation - Passes arguments as array instead of concatenated string - Eliminates shell redirection patterns (2>/dev/null) with try-catch blocks * fix(security): fix remaining command injection vulnerabilities and remove unused imports Fix all remaining CodeQL security warnings: CLI tool validation (cli-tool-manager.ts): - validateGit: Replace execSync with execFileSync for git --version Project initialization (project-initializer.ts): - Replace all 7 execSync calls with execFileSync - git rev-parse, git init, git status, git add, git commit Release service (release-service.ts): - checkTagExists: Fix git tag -l and git ls-remote - getGitHubReleaseUrl: Fix gh release view - Fix worktree merge detection (2 more git commands) - Remove unused execSync import Code cleanup: - Remove unused execSync imports from: - github/utils.ts - project-handlers.ts - settings-handlers.ts - release-service.ts Total: 12 additional command injection fixes + 4 unused imports removed This completes the security audit with 0 remaining vulnerabilities. * refactor(code-quality): remove useless variable assignments Fix CodeQL warnings about unused initial variable values: - mainBranch: Declare without initial value, assign in try-catch - unmergedCommits: Declare without initial value, assign in try-catch The initial values were never used since they were always overwritten either in the try block (success) or catch block (error fallback). * test(security): update oauth-handlers tests to use execFileSync mocks Update test mocks in oauth-handlers.spec.ts to match the security fix that changed from execSync to execFileSync. All 525 tests now passing. Changes: - gh CLI Check Handler tests: Use mockExecFileSync with array args - gh Auth Check Handler tests: Use mockExecFileSync with array args - Fixed argument pattern: cmd + args array instead of single command string Related to command injection prevention in oauth-handlers.ts
…90#348) ## Backend - Delete `agents/auto_claude_tools.py` (compatibility shim) - Delete `implementation_plan/main.py` (compatibility shim) - Remove `--dev` flag and `dev_mode` parameter from: - cli/main.py, cli/utils.py, cli/spec_commands.py - runners/spec_runner.py - spec/pipeline/models.py, orchestrator.py - spec/complexity.py - Remove `ClaudeSimilarityDetector` class from batch_issues.py - Remove unused `self.detector` alias ## Frontend - Remove `PROJECT_UPDATE_AUTOBUILD` IPC channel - Remove `updateProjectAutoBuild` from: - project-handlers.ts (IPC handler) - project-api.ts (preload API) - project-store.ts (store function) - project-mock.ts (mock) - Remove deprecated `appendOutput`/`clearOutputBuffer` from terminal-store - Update useTerminalEvents to use terminalBufferManager directly - Remove deprecated "Update Auto Claude" dialog from Sidebar - Remove `handleUpdate` from useProjectSettings hook ## Tests - Remove `test_dev_mode_param_ignored` test
… review (AndyMik90#347) * feat: add dropdown to select inbuilt or external terminal in task review Replace the single terminal button on the task review modal with a dropdown menu that allows users to choose between: - Opening in an inbuilt terminal tab (existing behavior) - Opening in the system's default external terminal application Changes: - Add IPC channel SHELL_OPEN_TERMINAL for opening paths in system terminal - Create IPC handler with cross-platform support (macOS, Windows, Linux) - Update ShellAPI with openTerminal method - Extend useTerminalHandler hook to support both terminal types - Create TerminalDropdown component with dropdown menu UI - Update WorkspaceStatus to use dropdown for both terminal buttons Cross-platform support: - macOS: Uses 'open -a Terminal' to open Terminal.app - Windows: Uses 'start cmd' to open Command Prompt - Linux: Tries common terminal emulators (gnome-terminal, konsole, xfce4-terminal, xterm) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: correct import paths in TerminalDropdown component * feat: add modal close and view switch for inbuilt terminal option When opening the inbuilt terminal from the task review modal, the UI now: - Closes the task detail modal - Switches to the Agent Terminals view - Creates the terminal in that view This provides a better user experience by automatically navigating to where the terminal is created, rather than keeping the user in the modal. Changes: - Added onSwitchToTerminals prop to TaskDetailModal, TaskReview, and WorkspaceStatus - Updated TerminalDropdown handlers to call onClose and onSwitchToTerminals before creating terminal - Wired up App.tsx to pass setActiveView callback to TaskDetailModal 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: pass terminal creation callback to parent to prevent unmount race condition The previous implementation called openTerminal from the WorkspaceStatus component, but when the modal closed and view switched, the component unmounted before the terminal could be created. This fix passes terminal creation parameters up to App.tsx where the modal close, view switch, and terminal creation are handled in the correct order at the parent level. Changes: - Added onOpenInbuiltTerminal callback prop through component hierarchy (TaskDetailModal → TaskReview → WorkspaceStatus) - Created handleOpenInbuiltTerminal in App.tsx that: 1. Closes the modal (setSelectedTask(null)) 2. Switches to terminals view (setActiveView('terminals')) 3. Creates the terminal (window.electronAPI.createTerminal) - Updated TerminalDropdown handlers in WorkspaceStatus to call the callback instead of creating terminal directly 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: add terminal to frontend store to display in UI The previous implementation created the terminal in the backend but didn't add it to the frontend terminal store, so TerminalGrid had no terminal to render. The correct flow is: 1. Add terminal to store (creates Terminal object in frontend) 2. Terminal component mounts 3. usePtyProcess hook creates backend PTY process Changes: - Updated handleOpenInbuiltTerminal to use useTerminalStore.getState().addTerminal() - Removed direct window.electronAPI.createTerminal() call - Terminal now appears in TerminalGrid after creation 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: add openTerminal to ElectronAPI type and browser mock TypeScript was complaining about missing openTerminal method: - Added openTerminal to ElectronAPI interface in ipc.ts - Added openTerminal mock to infrastructure-mock.ts for browser mode This fixes the typecheck errors in CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: use node: prefix for child_process import for better TypeScript resolution Changed from 'child_process' to 'node:child_process' to ensure TypeScript properly resolves the execSync import in all environments including CI. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * refactor: improve terminal command security, deterministic mounting, and i18n This commit addresses several issues with the terminal dropdown feature: 1. **Improved Windows Command Security** (settings-handlers.ts): - Removed fragile nested quotes from Windows terminal command - Changed from `"cd /d "${dirPath}""` to `cd /d "${sanitizedPath}"` - Added path sanitization to escape double quotes and prevent command injection - Simplified command structure for better reliability 2. **Deterministic Component Readiness** (App.tsx, TerminalGrid.tsx): - Replaced hardcoded 100ms timeout with deterministic readiness signal - Added `onMounted` prop to TerminalGrid that fires when component mounts - Created Promise-based waiting mechanism in handleOpenInbuiltTerminal - Checks if terminals view is already active to avoid unnecessary waiting - Ensures Terminal component is mounted before creating backend PTY 3. **i18n Compliance** (TerminalDropdown.tsx): - Replaced all hardcoded English strings with translation keys - Added useTranslation hook with 'taskReview' namespace - Updated button title: "Open terminal" → t('terminal.openTerminal') - Updated menu items: - "Open in Inbuilt Terminal" → t('terminal.openInbuilt') - "Open in External Terminal" → t('terminal.openExternal') - Created taskReview.json translation files for English and French Files Changed: - src/main/ipc-handlers/settings-handlers.ts - src/renderer/App.tsx - src/renderer/components/TerminalGrid.tsx - src/renderer/components/task-detail/task-review/TerminalDropdown.tsx - src/shared/i18n/locales/en/taskReview.json (new) - src/shared/i18n/locales/fr/taskReview.json (new) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: use execFileSync with argument arrays to prevent command injection Security Fix: Replaced all execSync shell commands with execFileSync and argument arrays to completely eliminate command injection vulnerabilities. Previous issue: - Incomplete escaping: only escaped double quotes, not backslashes - Shell interpretation could lead to command injection with crafted paths Solution: - macOS: execFileSync('open', ['-a', 'Terminal', dirPath]) - Windows: execFileSync('cmd.exe', ['/K', 'cd', '/d', dirPath], {shell: false}) - Linux: execFileSync(terminal, ['--working-directory', dirPath]) Benefits: - No shell interpretation - arguments passed directly to executables - No escaping needed - OS handles path special characters correctly - Prevents all forms of command injection - More reliable cross-platform behavior For xterm (Linux fallback), single quotes are properly escaped using the pattern: dirPath.replace(/'/g, "'\\''") which handles single quotes in paths. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: register taskReview namespace with i18n configuration The taskReview translation files were created but not registered with the i18n configuration, causing translation keys to be displayed literally instead of the actual translated text. Changes: - Imported enTaskReview and frTaskReview translation files - Added taskReview to resources object for both en and fr - Added 'taskReview' to the ns (namespaces) array in i18n.init() This fixes the dropdown menu displaying "terminal.openInbuilt" instead of "Open in Inbuilt Terminal". 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: remove unused onMounted callback and Promise-based readiness signaling - Remove handleTerminalGridMounted function reference that caused runtime error - Remove onMounted prop from TerminalGrid interface - Remove useEffect hook that called onMounted callback - Simplify handleOpenInbuiltTerminal to directly add terminal to store - TerminalGrid is always mounted (just hidden), so no readiness signaling needed This fixes "handleTerminalGridMounted is not defined" error and simplifies the terminal creation flow. * chore: remove unused imports (useRef, useCallback) from App.tsx * refactor: add input validation and remove unused import in terminal handler Security and code quality improvements: 1. Add comprehensive input validation for dirPath: - Check for non-empty string - Resolve to absolute path with path.resolve() - Verify path exists with existsSync() - Confirm it's a directory with statSync().isDirectory() - Return clear, actionable error messages if any check fails 2. Replace all uses of dirPath with validated resolvedPath 3. Remove unused execSync import from node:child_process 4. Add statSync to fs imports for directory validation This prevents potential issues with invalid paths and improves error handling with specific error messages for each validation failure. * refactor: rename unused id parameter to _id in handleOpenInbuiltTerminal - Prefix parameter with underscore to indicate intentionally unused - Add comment explaining terminal ID is auto-generated by addTerminal() - Keep parameter for callback signature consistency with callers - Remove id from console.log since it's not used in the logic This satisfies linter requirements while maintaining callback compatibility. --------- Co-authored-by: Claude Sonnet 4.5 <[email protected]>
🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]>
Fixes AndyMik90#235 The Edit Task modal's close button (X) was unresponsive because both the parent modal and the edit dialog used z-50 for their overlays. The parent's overlay intercepted clicks meant for the edit dialog's close button. This fix hides the parent modal while the Edit dialog is open, then reopens it when the Edit dialog closes. This is a cleaner UX than z-index hacks. Signed-off-by: Black Circle Sentinel <[email protected]>
* fix: make backend tests pass on Windows * fix: address Windows locking + lazy graphiti imports * fix: address CodeRabbit review comments * fix: improve file_lock typing * Update apps/backend/runners/github/file_lock.py Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: satisfy ruff + asyncio loop usage * style: ruff format file_lock * refactor: safer temp file close + async JSON read * style: ruff format file_lock --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Andy <[email protected]>
AndyMik90#351) * fix(analyzer): add C#/Java/Swift/Kotlin project files to security hash Fixes AndyMik90#222 The security profile hash calculation was missing key config files for several languages, causing the profile not to regenerate when: - C# projects (.csproj, .sln, .fsproj, .vbproj) changed - Java/Kotlin/Scala projects (pom.xml, build.gradle, etc.) changed - Swift packages (Package.swift) changed Changes: - Add Java, Kotlin, Scala, Swift config files to hash_files list - Add glob patterns for .NET project files (can be anywhere in tree) - Update fallback source extensions to include .cs, .swift, .kt, .java Signed-off-by: Black Circle Sentinel <[email protected]> * fix(analyzer): replace empty except pass with continue --------- Signed-off-by: Black Circle Sentinel <[email protected]> Co-authored-by: Andy <[email protected]>
…ik90#358) * fix(terminal): preserve terminal state when switching projects Fixes terminal state loss when switching between project tabs (AndyMik90#342). Two issues addressed: 1. PTY health check: Added checkTerminalPtyAlive IPC method to detect terminals with stale state (no live PTY process). restoreTerminalSessions now removes dead terminals and restores from disk instead of skipping. 2. Buffer preservation: Added SerializeAddon to capture terminal buffer with ANSI escape codes before disposal. This preserves the shell prompt, colors, and output history when switching back to a project. Closes AndyMik90#342 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix(terminal): address PR review findings Addresses 5 findings from Auto Claude PR Review: 1. [HIGH] Race condition protection: Added restoringProjects Set to prevent concurrent restore calls for the same project 2. [HIGH] Unnecessary disk restore: Skip disk restore when some terminals are still alive to avoid duplicates 3. [HIGH] Double dispose vulnerability: Added isDisposedRef guard to prevent corrupted serialization on rapid unmount/StrictMode 4. [MEDIUM] SerializeAddon disposal: Explicitly call dispose() before setting ref to null 5. [MEDIUM] projectPath validation: Added input validation at function start 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix(terminal): allow disk restore when alive terminals exist CodeRabbit review finding: When a project has mixed alive and dead terminals, the early return was preventing disk restore, causing dead terminals to be permanently lost. The fix removes the early return since addRestoredTerminal() already has duplicate protection (checks terminal ID before adding). This allows dead terminals to be safely restored from disk while alive terminals remain unaffected. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix(terminal): remove unused aliveTerminals variable CodeQL flagged unused variable after previous fix removed the early return that was using it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Opus 4.5 <[email protected]>
… ruff version, and broken quality-dco workflow (AndyMik90#334) * fix: Fixes issues to get clean pre-commit run 1. version-sync hook was failing due to formatting, fixed with block scalar. 2. Python Tests step was failing because it could not locate python or pytest. Fixed by referencing pytest in .venv, [as was shown here in CONTRIBUTING.md](https://github.com/AndyMik90/Auto-Claude/blob/develop/CONTRIBUTING.md?plain=1#L299) At this point pre-commit could run, then there were a few issues it found that had to be fixed: 3. "check yaml" hook failed for the file ".github/workflows/quality-dco.yml". Fixed indenting issue. 4. Various files had whitespace issues that were auto-fixed by the pre-commit commands. After this, "pre-commit run --all-files" passes for all checks. Signed-off-by: Ian <[email protected]> * docs: Update CONTRIBUTING.md with cmake dependency cmake is not present by default on macs, can be installed via homebrew Signed-off-by: Ian <[email protected]> * Addressed PR comments on file consistency and install instructions. Signed-off-by: Ian <[email protected]> * Ran pre-commit autoupdate, disabled broken quality-dco workflow The version of ruff in pre-commit was on a much older version than what was running as part of the lint github workflow. This caused it to make changes that were rejected by the newer version. As far as disabling quality-dco workflow; according to https://github.com/AndyMik90/Auto-Claude/actions/workflows/quality-dco.yml, it has never actually successfully parsed since it was introduced in AndyMik90#266, and so it has not been running on any PRs to date. Given that, plus the fact that I see no mention/discussion of Developer Certificate of Origin in any github issues or the discord, I will run with the assumption this needs more explicit discussion before we turn it on and force all contributors to add these signoffs for every commit. Signed-off-by: Ian <[email protected]> * Fixed bad sed command in pre-commit version-sync hook It resulted in bad version names being produced for beta versions, such as "Auto-Claude-2.7.2-beta.9-beta.9-arm64.dmg". Also addressed PR comment for needed spacing in markdown code blocks. Signed-off-by: Ian <[email protected]> * Fixed other sed command for version sync to avoid incorrect names Addresses PR comment to keep this in line with existing sed command fix in the same PR. Signed-off-by: Ian <[email protected]> * Keep version of ruff in sync between pre-commit and github workflow This will avoid situations where the checks done locally and in CI start to diverge and even conflict Signed-off-by: Ian <[email protected]> * Enabling DCO workflow Signed-off-by: Ian <[email protected]> * Fixed windows compatibility issue for running pytest Also committing some more file whitespace changes made by the working pre-commit hook. Signed-off-by: Ian <[email protected]> * Removed out of date disabled banner on quality dco workflow Signed-off-by: Ian <[email protected]> * Fixed version-sync issue with incorrect version badge image url, fixed dco workflow Updated readme with correct value as well Fixed DCO workflow as it was pointing at a nonexistent step. Improved DCO workflow failure message to warn about accidentally signing others commits. --------- Signed-off-by: Ian <[email protected]> Co-authored-by: Andy <[email protected]>
* fix(subprocess): handle Python paths with spaces Fixes AndyMik90#315 The packaged macOS app uses a Python path inside ~/Library/Application Support/ which contains a space. The subprocess-runner.ts was passing the path directly to spawn(), causing ENOENT errors. This fix adds parsePythonCommand() (already used by agent-process.ts) to properly handle paths with spaces. This also affects Changelog generation and other GitHub automation features. Signed-off-by: Black Circle Sentinel <[email protected]> * test(subprocess): add unit tests for python path spaces and arg ordering --------- Signed-off-by: Black Circle Sentinel <[email protected]> Co-authored-by: Andy <[email protected]>
…AndyMik90#355) * fix(security): invalidate profile cache when file is created/modified Fixes AndyMik90#153 The security profile cache was returning stale data even after the .auto-claude-security.json file was created or updated. This caused commands like 'dotnet' to be blocked even when present in the file. Root cause: get_security_profile() cached the profile on first call without checking if the file's mtime changed on subsequent calls. Fix: Track the security profile file's mtime and invalidate the cache when the file is created (mtime goes from None to a value) or modified (mtime changes). This also helps with issue AndyMik90#222 where the profile is created after the agent starts - now the agent will pick up the new profile on the next command validation. Signed-off-by: Black Circle Sentinel <[email protected]> * fix(security): handle deleted profile file and add cache invalidation tests * fix(security): handle deleted profile file and add cache invalidation tests * test(security): improve cache tests with mocks and unique commands * test(security): add mock-free tests for cache invalidation * test(security): fix cache invalidation tests without mocks * fix(security): address review comments and add debug logs for CI hash failure * fix(analyzer): remove debug prints * fix(lint): sort imports in profile.py * fix(security): include spec_dir in cache key to prevent stale profiles The cache key previously only included project_dir, but the profile location can depend on spec_dir. This could cause stale cached profiles to be returned if spec_dir changes between calls. Fix: Add _cached_spec_dir to the cache validation logic and reset function. --------- Signed-off-by: Black Circle Sentinel <[email protected]> Co-authored-by: Andy <[email protected]>
…op (AndyMik90#362) The projectTabs array was being included in the useEffect dependency array, but since it's computed fresh on every render (via getProjectTabs()), it always has a new reference. This caused the effect to fire on every render cycle, creating an infinite re-render loop. Fix: Use openProjectIds.includes() instead of projectTabs.some() since openProjectIds is stable state and already tracks the same information. Fixes performance regression in beta.10 where UI interactions took 5-6 seconds. Co-authored-by: Andy <[email protected]>
* fix:scaling - in the settings pane, when changing the scale size by dragging the icon across the bar, the view reloads as you are doing it so it makes it difficult to change the scale properly. also the - and + buttons don't increase or decrease the scale by 5%. these have now been fixed. * added NaN guard * added type=button --------- Co-authored-by: Andy <[email protected]>
Add documentation from security review: - PROMPT_INJECTION_DEFENSE.md: Attack taxonomy, defenses, and checklist - DOCKER_NATIVE_DESIGN.md: Docker-native architecture design for containerized deployment These documents provide security guidance and future architecture plans discovered during the security hardening work. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <[email protected]> Co-authored-by: Andy <[email protected]>
…updates them (AndyMik90#378) Both download links and the shields badge version link. Signed-off-by: Ian <[email protected]>
…ik90#336) (AndyMik90#373) The Graph Memory Status card now correctly validates the configured embedding provider (GRAPHITI_EMBEDDER_PROVIDER) instead of always requiring OPENAI_API_KEY. Supported providers: - openai (default, requires OPENAI_API_KEY) - ollama (local, no API key needed) - google (requires GOOGLE_API_KEY) - voyage (requires VOYAGE_API_KEY) - azure_openai (requires AZURE_OPENAI_API_KEY) Changes: - Add validateEmbeddingConfiguration() in utils.ts - Update memory-status-handlers.ts to use new validation - Display provider-specific error messages when keys are missing Fixes AndyMik90#336 Signed-off-by: Black Circle Sentinel <[email protected]> Co-authored-by: Alex <[email protected]>
… true when gh CLI is found" (AndyMik90#370) A mock appears to have been broken by this change: AndyMik90@39e09e3#diff-dbd75baa12f1f8dd98fe6c6fec63160b8be291bc8de4d2970e993e1081746ba0L110-R121 I ran into a failure on this test when setting up for the first time locally and running frontend tests. I expect this did not break elsewhere because others actually have the github CLI installed, and so it was not noticed that the code under test executed the real filesystem commands to find it, and succeeded when doing so. But I do not have github CLI installed, and the test failed for me. Signed-off-by: Ian <[email protected]> Co-authored-by: Andy <[email protected]>
…ideation type (AndyMik90#381) Adjusted the progress calculation in the ideation store to account for the newly completed ideation type. This change ensures that the state updates are accurately reflected, especially with React 18's batching behavior. The updated logic now includes the completed type in the calculation of completed counts, improving the accuracy of progress tracking. Co-authored-by: Andy <[email protected]>
…rt (AndyMik90#363) * docs: add PR hygiene guidelines to CONTRIBUTING.md This update introduces a new section on PR hygiene, outlining best practices for rebasing, commit organization, and maintaining small PR sizes. It emphasizes the importance of keeping a clean commit history and provides commands for ensuring branches are up-to-date before requesting reviews. These guidelines aim to improve the overall quality and efficiency of pull requests in the project. Signed-off-by: AndyMik90 <[email protected]> * fix(github-pr): use commit SHAs for PR context gathering and add debug logging Fixes GitHub PR review failing to retrieve file patches when PR branches aren't fetched locally (e.g., fork PRs, deleted branches). The context gatherer now fetches commit SHAs (headRefOid/baseRefOid) from GitHub API and uses them instead of branch names for git operations. Also adds comprehensive debug logging for the orchestrator reviewer: - Shows LLM thinking blocks and response streaming in DEBUG mode - Passes DEBUG env var through to Python subprocess - Adds status messages during long-running LLM calls Changes: - context_gatherer.py: Add _ensure_pr_refs_available() to fetch commits - orchestrator_reviewer.py: Add DEBUG_MODE logging for LLM interactions - subprocess-runner.ts: Pass DEBUG env var to Python subprocess - pydantic_models.py: Add structured output models for PR review 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> Signed-off-by: AndyMik90 <[email protected]> * fix(github-pr): fix confidence conversion bugs in orchestrator reviewer Fixed 4 instances of broken confidence conversion logic: - Dead code where both ternary branches were identical (divided by 100) - Multiple data.get() calls with different defaults (85, 85, 0.85) Added _normalize_confidence() helper method that properly handles: - Percentage values (0-100): divides by 100 - Decimal values (0.0-1.0): uses as-is 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> Signed-off-by: AndyMik90 <[email protected]> * fix(github-pr): address review findings and fix confidence normalization Address Auto Claude PR review findings: - Add Pydantic field_validator for confidence normalization (0-100 → 0.0-1.0) - Add path/ref validation helpers for command injection defense - Add fallback to text parsing when structured output fails - Sync category mapping between orchestrator and followup reviewer - Add security comment for DEBUG env var passthrough - Fix constraint from le=100.0 to le=1.0 for normalized confidence - Update tests to expect normalized confidence values 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> Signed-off-by: AndyMik90 <[email protected]> * fix(github): extract structured output from SDK ToolUseBlock The Claude Agent SDK delivers structured outputs via a ToolUseBlock named 'StructuredOutput' in AssistantMessage.content, not in a structured_output attribute on the message. This was causing reviews to fall back to heuristic parsing instead of using validated JSON. Changes: - followup_reviewer: increased max_turns from 1 to 2 (structured output requires tool call + response), now extracts data from ToolUseBlock with name='StructuredOutput' - orchestrator_reviewer: added handling for StructuredOutput tool in both ToolUseBlock messages and AssistantMessage content - Added SDK structured output integration test 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: AndyMik90 <[email protected]> * fix(github-pr): address Cursor review findings - Fix empty findings fallback logic: return None from _parse_structured_output on parsing failure instead of empty list, so clean PRs don't trigger unnecessary text parsing fallback - Handle _ensure_pr_refs_available return value: log warning if PR refs can't be fetched locally (will use GitHub API patches as fallback) - Add missing "docs" and "style" categories to OrchestratorFinding schema to match ReviewCategory enum and prevent validation failures 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> Signed-off-by: AndyMik90 <[email protected]> * cleanup --------- Signed-off-by: AndyMik90 <[email protected]> Co-authored-by: Claude Opus 4.5 <[email protected]>
…s-badge-for-top-bar
…ik90#1025) * feat(sentry): integrate Sentry configuration into Electron build - Added build-time constants for Sentry DSN and sampling rates in electron.vite.config.ts. - Enhanced environment variable handling in env-utils.ts to include Sentry settings for subprocesses. - Implemented getSentryEnvForSubprocess function in sentry.ts to provide Sentry environment variables for Python backends. - Updated Sentry-related functions to prioritize build-time constants over runtime environment variables for improved reliability. This integration ensures that Sentry is properly configured for both local development and CI environments. * fix(sentry): add typeof guards for build-time constants in tests The __SENTRY_*__ constants are only defined when Vite's define plugin runs during build. In test environments (vitest), these constants are undefined and cause ReferenceError. Added typeof guards to safely handle both cases. Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Opus 4.5 <[email protected]>
AndyMik90
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤖 Auto Claude PR Review
🟠 Follow-up Review: Needs Revision
🟠 Needs revision - 1 blocking issue(s) require fixes.
Resolution Status
- ✅ Resolved: 0 previous findings addressed
- ❌ Unresolved: 0 previous findings remain
- 🆕 New Issues: 3 new findings in recent changes
Finding Validation
- 🔍 Dismissed as False Positives: 1 findings were re-investigated and found to be incorrect
- ✓ Confirmed Valid: 1 findings verified as genuine issues
- 👤 Needs Human Review: 0 findings require manual verification
🚨 Blocking Issues
- quality: useApiMethod flag permanently disabled on first API failure
Verdict
CI Status: ✅ All 18 checks passing - no CI blockers.
Finding Analysis:
- 1 MEDIUM severity finding CONFIRMED VALID (NEW-002: useApiMethod flag never reset after API failure)
- 1 MEDIUM severity finding DISMISSED as false positive (NEW-001: NaN timestamps - protected by falsy checks)
- 2 LOW severity suggestions (bounds validation for API percentages)
Why NEEDS_REVISION: Per quality gates, MEDIUM severity findings that are CONFIRMED_VALID (not dismissed as false positive) block merge. NEW-002 is a legitimate logic issue where the UsageMonitor singleton permanently falls back to CLI after a single transient API failure. While the functionality still works via CLI, this is suboptimal behavior that should be addressed with a retry mechanism.
To resolve: Add logic to periodically retry the API method after it has been disabled, such as resetting useApiMethod to true after N successful CLI calls or implementing exponential backoff.
Review Process
Agents invoked: new-code-reviewer, finding-validator
This is an AI-generated follow-up review using parallel specialist analysis with finding validation.
Findings (2 selected of 3 total)
🔵 [NEW-003] [LOW] Z.ai API percentage values used without bounds validation
📁 apps/frontend/src/main/services/profile/profile-usage.ts:159
The Z.ai API response's percentage field is used directly without validating it's within expected bounds (0-100). If the API returns malformed data, this could cause unexpected UI behavior.
Suggested fix:
Add bounds clamping: Math.max(0, Math.min(100, tokensLimit?.percentage ?? 0))
🔵 [NEW-004] [LOW] Anthropic OAuth utilization values used without bounds validation
📁 apps/frontend/src/main/services/profile/profile-usage.ts:250
The Anthropic OAuth API utilization values (0.0-1.0) are multiplied by 100 without bounds validation. Out-of-range API responses could cause incorrect percentage displays.
Suggested fix:
Add bounds clamping after multiplication: Math.max(0, Math.min(100, ...))
This review was generated by Auto Claude.
…1021) * auto-claude: subtask-1-1 - Add convertingIdeas state and guard logic to useIdeation hook * auto-claude: subtask-1-2 - Update IdeaDetailPanel to accept isConverting prop * auto-claude: subtask-2-1 - Add idempotency check for linked_task_id in task-c * auto-claude: subtask-3-1 - Manual testing: Verify rapid clicking creates only one task - Fixed missing convertingIdeas prop connection in Ideation.tsx - Added convertingIdeas to destructured hook values - Added isConverting prop to IdeaDetailPanel component - Created detailed manual-test-report.md with code review and E2E testing instructions - All code implementation verified via TypeScript checks (no errors) - Multi-layer protection confirmed: UI disabled, guard check, backend idempotency - Manual E2E testing required for final verification Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: address PR review findings for duplicate task prevention - Fix TOCTOU race condition by moving idempotency check inside lock - Fix React state closure by using ref for synchronous tracking - Add i18n translations for ideation UI (EN + FR) - Add error handling with toast notifications for conversion failures Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Sonnet 4.5 <[email protected]>
…p-permissions (AndyMik90#1016) * feat(terminal): add YOLO mode to invoke Claude with --dangerously-skip-permissions Add a toggle in Developer Tools settings that enables "YOLO Mode" which starts Claude with the --dangerously-skip-permissions flag, bypassing all safety prompts. Changes: - Add dangerouslySkipPermissions setting to AppSettings interface - Add translation keys for YOLO mode (en/fr) - Modify claude-integration-handler to accept and append extra flags - Update terminal-manager and terminal-handlers to read and forward the setting - Add Switch toggle with warning styling in DevToolsSettings UI The toggle includes visual warnings (amber colors, AlertTriangle icon) to clearly indicate this is a dangerous option that bypasses Claude's permission system. Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix(terminal): address PR review issues for YOLO mode implementation - Add async readSettingsFileAsync to avoid blocking main process during settings read - Extract YOLO_MODE_FLAG constant to eliminate duplicate flag strings - Store dangerouslySkipPermissions on terminal object to persist YOLO mode across profile switches - Update switchClaudeProfile callback to pass stored YOLO mode setting These fixes address: - LOW: Synchronous file I/O in IPC handler - LOW: Flag string duplicated in invokeClaude and invokeClaudeAsync - MEDIUM: YOLO mode not persisting when switching Claude profiles Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Opus 4.5 <[email protected]>
* auto-claude: subtask-1-1 - Add i18n translation keys for worktree notice banner and merge tooltip - Added wizard.worktreeNotice.title and wizard.worktreeNotice.description for task creation banner - Added review.mergeTooltip for merge button explanation - Translations added to both en/tasks.json and fr/tasks.json * auto-claude: subtask-1-2 - Add visible info banner to TaskCreationWizard expl * auto-claude: subtask-1-3 - Add tooltip to 'Merge with AI' button in WorkspaceStatus - Import Tooltip components from ui/tooltip - Wrap merge button with Tooltip, TooltipTrigger, TooltipContent - Add contextual tooltip text explaining merge operation: * With AI: explains worktree merge, removal, and AI conflict resolution * Without AI: explains worktree merge and removal - Follows Radix UI tooltip pattern from reference file * fix: use i18n key for merge button tooltip in WorkspaceStatus * fix: clarify merge tooltip - worktree removal is optional (qa-requested) Fixes misleading tooltip text that implied worktree is automatically removed during merge. In reality, after merge, users are shown a dialog where they can choose to keep or remove the worktree. Updated tooltip to reflect this flow. Changes: - Updated en/tasks.json: Changed tooltip to clarify worktree removal is optional - Updated fr/tasks.json: Updated French translation to match QA Feedback: "Its currently saying on the tooltip that it will 'remove the worktree' Please validate if this is the actual logic. As per my understanding, there will be an extra button afterwards that will make sure that the user has access to the work tree if they want to revert anything. The user has to manually accept to remove the work tree." Co-Authored-By: Claude Sonnet 4.5 <[email protected]> * fix: use theme-aware colors for worktree info banner Replace hardcoded blue colors with semantic theme classes to support dark mode properly. Uses the same pattern as other info banners in the codebase (bg-info/10, border-info/30, text-info). Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Sonnet 4.5 <[email protected]>
* fix(terminal): improve worktree name input to not strip trailing characters while typing - Allow trailing hyphens/underscores during input (only trim on submit) - Add preview name that shows the final sanitized value for branch preview - Remove invalid characters instead of replacing with hyphens - Collapse consecutive underscores in addition to hyphens - Final sanitization happens on submit to match backend WORKTREE_NAME_REGEX Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix(terminal): address PR review findings for worktree name validation - Fix submit button disabled check to use sanitized name instead of raw input - Simplify trailing trim logic (apply once after all transformations) - Apply lowercase in handleNameChange to reduce input/preview gap - Internationalize 'name' fallback using existing translation key Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix(terminal): improve header responsiveness for multiple terminals - Hide text labels (Claude, Open in IDE) when ≥4 terminals, show icon only - Add dynamic max-width to worktree name badge with truncation - Add tooltips to all icon-only elements for accessibility - Maintain full functionality while reducing header width requirements Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Opus 4.5 <[email protected]> Co-authored-by: Test User <[email protected]>
…AndyMik90#1013) * fix(terminal): enhance terminal recreation logic with retry mechanism - Introduced a maximum retry limit and delay for terminal recreation when dimensions are not ready. - Added cleanup for retry timers on component unmount to prevent memory leaks. - Improved error handling to report failures after exceeding retry attempts, ensuring better user feedback during terminal setup. * fix(terminal): address PR review feedback for retry mechanism - Fix race condition: clear pending retry timer at START of effect to prevent multiple timers when dependencies change mid-retry - Fix isCreatingRef: keep it true during retry window to prevent duplicate creation attempts from concurrent effect runs - Extract duplicated retry logic into scheduleRetryOrFail helper (consolidated 5 duplicate instances into 1 reusable function) - Add handleSuccess/handleError helpers to reduce code duplication - Reduce file from 295 to 237 lines (~20% reduction) Addresses review feedback from CodeRabbit, Gemini, and Auto Claude. Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Test User <[email protected]> Co-authored-by: Claude Opus 4.5 <[email protected]>
- Add retry mechanism for API method after N successful CLI calls - Add bounds validation for Z.ai API percentage values (0-100) - Add bounds validation for Anthropic OAuth utilization values (0-100) This fixes the blocking issue where useApiMethod flag was permanently disabled after a single transient API failure. Now the system will retry the API method after 5 consecutive successful CLI fallbacks.
…s-badge-for-top-bar
The usage badge wasn't showing because: 1. The initializeUsageMonitorForwarding function existed but was missing event listeners for proactive-swap-completed and proactive-swap-failed events 2. Added missing event listeners for proactive swap notifications 3. Added safety checks to prevent sending to destroyed windows The UsageMonitor is already started by main.ts after profile manager initialization. This fix ensures the events are properly forwarded to the renderer process so the UI can display the usage badge.
…ndyMik90#1033) * feat(terminal): add task worktrees section and remove terminal limit - Remove 12 terminal worktree limit (now unlimited) - Add "Task Worktrees" section in worktree dropdown below terminal worktrees - Task worktrees (created by kanban) now accessible for manual work - Update translations for new section labels (EN + FR) Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix(terminal): address PR review feedback - Clear taskWorktrees state when project is null or changes - Parallelize API calls with Promise.all for better performance - Use consistent path-based filtering for both worktree types - Add clarifying comment for createdAt timestamp Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Opus 4.5 <[email protected]> Co-authored-by: Test User <[email protected]>
…s-badge-for-top-bar
* auto-claude: subtask-1-1 - Add feedbackImages state and handlers to useTaskDetail - Add feedbackImages state as ImageAttachment[] for storing feedback images - Add setFeedbackImages setter for direct state updates - Add addFeedbackImage handler for adding a single image - Add addFeedbackImages handler for adding multiple images at once - Add removeFeedbackImage handler for removing an image by ID - Add clearFeedbackImages handler for clearing all images - Import ImageAttachment type from shared/types 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * auto-claude: subtask-1-2 - Update IPC interface to support images in submitReview - Add ImageAttachment import from ./task types - Update submitReview signature to include optional images parameter 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <[email protected]> * auto-claude: subtask-1-3 - Update submitReview function in task-store to accept and pass images * auto-claude: subtask-2-1 - Add paste/drop handlers and image thumbnail displa - Add paste event handler for screenshot/image clipboard support - Add drag-over and drag-leave handlers for visual feedback during drag - Add drop handler for image file drops - Add image thumbnail display (64x64) with remove button on hover - Import image utilities from ImageUpload.tsx (generateImageId, blobToBase64, etc.) - Add i18n support for all new UI text - Make new props optional for backward compatibility during incremental rollout - Allow submission with either text feedback or images (not both required) - Add visual drag feedback with border/background color change * auto-claude: subtask-2-2 - Update TaskReview to pass image props to QAFeedbackSection * auto-claude: subtask-2-3 - Update TaskDetailModal to manage image state and pass to TaskReview - Pass feedbackImages and setFeedbackImages from useTaskDetail hook to TaskReview - Update handleReject to include images in submitReview call - Allow submission with images only (no text required) - Clear images after successful submission * auto-claude: subtask-3-1 - Add English translations for feedback image UI * auto-claude: subtask-3-2 - Add French translations for feedback image UI * fix(security): sanitize image filename to prevent path traversal - Use path.basename() to strip directory components from filenames - Validate sanitized filename is not empty, '.', or '..' - Add defense-in-depth check verifying resolved path stays within target directory - Fix base64 data URL regex to handle complex MIME types (e.g., svg+xml) Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix: add MIME type validation and fix SVG file extension - Add server-side MIME type validation for image uploads (defense in depth) - Fix SVG file extension: map 'image/svg+xml' to '.svg' instead of '.svg+xml' - Add MIME-to-extension mapping for all allowed image types Co-Authored-By: Claude Opus 4.5 <[email protected]> * fix: require mimeType and apply SVG extension fix to drop handler - Change MIME validation to reject missing mimeType (prevents bypass) - Add 'image/jpg' to server-side allowlist for consistency - Apply mimeToExtension mapping to drop handler (was only in paste handler) Co-Authored-By: Claude Opus 4.5 <[email protected]> --------- Co-authored-by: Claude Opus 4.5 <[email protected]> Co-authored-by: Test User <[email protected]>
…dyMik90#1010) * fix(auth): await profile manager initialization before auth check Fixes race condition where hasValidAuth() was called before the ClaudeProfileManager finished async initialization from disk. The getClaudeProfileManager() returns a singleton immediately with default profile data (no OAuth token). When hasValidAuth() runs before initialization completes, it returns false even when valid credentials exist. Changed all pre-flight auth checks to use await initializeClaudeProfileManager() which ensures initialization completes via promise caching. Signed-off-by: StillKnotKnown <[email protected]> * fix(auth): add error handling for profile manager initialization Prevents unhandled promise rejections when initializeClaudeProfileManager() throws due to filesystem errors (permissions, disk full, corrupt JSON). The ipcMain.on handler for TASK_START doesn't await promises, so unhandled rejections could crash the main process. Wrapped all await initializeClaudeProfileManager() calls in try-catch blocks. Found via automated code review. Signed-off-by: StillKnotKnown <[email protected]> * test: mock initializeClaudeProfileManager in subprocess tests The test mock was only mocking getClaudeProfileManager, but now we also use initializeClaudeProfileManager which wasn't mocked, causing test failures. Signed-off-by: StillKnotKnown <[email protected]> * fix(auth): add try-catch for initializeClaudeProfileManager in remaining handlers Addresses PR review feedback - TASK_UPDATE_STATUS and TASK_RECOVER_STUCK handlers were missing try-catch blocks for initializeClaudeProfileManager(), inconsistent with TASK_START handler. If initialization fails, users now get specific file permissions guidance instead of generic error messages. Signed-off-by: StillKnotKnown <[email protected]> * refactor(auth): extract profile manager initialization into helper Extract the repeated initializeClaudeProfileManager() + try/catch pattern into a helper function ensureProfileManagerInitialized() that returns a discriminated union for type-safe error handling. This reduces code duplication across TASK_START, TASK_UPDATE_STATUS, and TASK_RECOVER_STUCK handlers while preserving context-specific error handling behavior. The helper returns: - { success: true, profileManager } on success - { success: false, error } on failure Signed-off-by: StillKnotKnown <[email protected]> * fix(auth): improve error details and allow retry after transient failures Two improvements to profile manager initialization: 1. Include actual error details in failure response for better debugging. Previously, only a generic message was returned to users, making it hard to diagnose the root cause. Now the error message is appended. 2. Reset cached promise on failure to allow retries after transient errors. Previously, if initialize() failed (e.g., EACCES, ENOSPC), the rejected promise was cached forever, requiring app restart to recover. Now the cached promise is reset on failure, allowing subsequent calls to retry. Signed-off-by: StillKnotKnown <[email protected]> --------- Signed-off-by: StillKnotKnown <[email protected]> Co-authored-by: StillKnotKnown <[email protected]> Co-authored-by: Andy <[email protected]>
…s-badge-for-top-bar
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In @apps/frontend/src/main/claude-profile/usage-monitor.ts:
- Around line 406-413: Wrap each parseResetTime call separately so a thrown
error for one reset string doesn't discard the whole snapshot: when computing
sessionResetTimestamp and weeklyResetTimestamp from usageData.sessionResetTime
and usageData.weeklyResetTime, catch errors per-call (e.g., try/catch or small
self-invoking helper) and return undefined on failure so parseResetTime
exceptions only affect that timestamp and not the other fields or the overall
snapshot.
- Around line 229-235: The code calls profilesFile.profiles.find(...) without
ensuring profilesFile.profiles exists or is an array; add a defensive guard
(e.g., check Array.isArray(profilesFile.profiles) or default to an empty array)
before using .find so that activeProfile assignment is safe, and if the guard
fails return null (or handle accordingly) instead of allowing a runtime
exception in the activeProfile lookup.
In @apps/frontend/src/main/ipc-handlers/terminal-handlers.ts:
- Around line 764-794: The handlers for monitor.on('proactive-swap-completed')
and monitor.on('proactive-swap-failed') use data: any — replace these with
explicit typed payloads (e.g., ProactiveSwapCompletedData and
ProactiveSwapFailedData) defined in a shared types file and import them into
terminal-handlers.ts, then update the event listener signatures to use those
interfaces (and likewise type the show-swap-notification parameter if you have a
Notification type); keep the existing mainWindow.isDestroyed() guards and ensure
the typed payloads match the IPC shape you send via
IPC_CHANNELS.PROACTIVE_SWAP_NOTIFICATION.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
apps/frontend/src/main/claude-profile/usage-monitor.tsapps/frontend/src/main/ipc-handlers/terminal-handlers.tsapps/frontend/src/main/services/profile/profile-usage.ts
🧰 Additional context used
📓 Path-based instructions (2)
apps/frontend/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/frontend/src/**/*.{tsx,ts}: Use i18n translation keys for all user-facing text in the frontend. All labels, buttons, messages must use translation keys from react-i18next with namespace:section.key format (e.g., 'navigation:items.githubPRs').
Never use hardcoded strings for UI text in JSX/TSX files. Always use translation keys via useTranslation() hook.
Files:
apps/frontend/src/main/claude-profile/usage-monitor.tsapps/frontend/src/main/ipc-handlers/terminal-handlers.tsapps/frontend/src/main/services/profile/profile-usage.ts
apps/frontend/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.
Files:
apps/frontend/src/main/claude-profile/usage-monitor.tsapps/frontend/src/main/ipc-handlers/terminal-handlers.tsapps/frontend/src/main/services/profile/profile-usage.ts
🧠 Learnings (2)
📚 Learning: 2026-01-12T13:47:32.539Z
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T13:47:32.539Z
Learning: Applies to apps/frontend/src/**/*.{tsx,ts} : Never use hardcoded strings for UI text in JSX/TSX files. Always use translation keys via useTranslation() hook.
Applied to files:
apps/frontend/src/main/services/profile/profile-usage.ts
📚 Learning: 2026-01-12T13:47:32.539Z
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T13:47:32.539Z
Learning: Applies to apps/frontend/src/**/*.{tsx,ts} : Use i18n translation keys for all user-facing text in the frontend. All labels, buttons, messages must use translation keys from react-i18next with namespace:section.key format (e.g., 'navigation:items.githubPRs').
Applied to files:
apps/frontend/src/main/services/profile/profile-usage.ts
🧬 Code graph analysis (2)
apps/frontend/src/main/claude-profile/usage-monitor.ts (2)
apps/frontend/src/main/services/profile/index.ts (4)
loadProfilesFile(10-10)detectProvider(36-36)fetchUsageForProfile(39-39)fetchAnthropicOAuthUsage(38-38)apps/frontend/src/main/services/profile/profile-usage.ts (3)
detectProvider(87-113)fetchUsageForProfile(291-312)fetchAnthropicOAuthUsage(207-277)
apps/frontend/src/main/ipc-handlers/terminal-handlers.ts (1)
apps/frontend/src/shared/constants/ipc.ts (1)
IPC_CHANNELS(6-524)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Seer Code Review
- GitHub Check: CodeQL (javascript-typescript)
- GitHub Check: CodeQL (python)
🔇 Additional comments (11)
apps/frontend/src/main/services/profile/profile-usage.ts (6)
22-30: LGTM on ApiAuthError class.Clean implementation of a custom error class with readonly properties and proper inheritance.
87-113: Provider detection logic is well-structured.The function correctly handles:
- Z.ai domain and subdomains
- Anthropic OAuth tokens (by prefix check)
- Graceful fallback for invalid URLs and unknown providers
123-192: Solid implementation with proper timeout handling and defensive guards.Good practices observed:
- AbortController for timeout management
- Bounds validation on percentages (
Math.max(0, Math.min(100, ...)))- Guard against malformed response (
Array.isArraycheck on line 152)- Proper error handling for AbortError and general exceptions
291-312: Clean routing implementation.The switch-based dispatch is clear and handles all provider types appropriately with consistent null returns for unsupported cases.
322-340: LGTM on the reset time formatter.The function correctly handles edge cases (past timestamps, short durations) and produces human-readable output. The
RESETTING_SOONsentinel for imminent resets aligns with the UI requirements.
219-227: Verify the Anthropic API version header is current.The
anthropic-version: 2023-06-01header may be outdated. Confirm this is the correct version for the OAuth usage endpoint.What is the latest Anthropic API version header value?apps/frontend/src/main/claude-profile/usage-monitor.ts (5)
36-39: Good addition of retry mechanism constants.The CLI fallback retry threshold (5 consecutive successes before retrying API) is a reasonable heuristic to avoid permanent fallback while not thrashing between methods.
136-176: Appropriate scoping of proactive swap to OAuth profiles only.The check at line 138 correctly ensures that automatic profile switching only occurs for
anthropic-oauthproviders, as Z.ai and other API profiles don't support multi-account switching. The threshold logic is sound.
309-323: LGTM on the CLI fallback retry mechanism.The implementation correctly tracks consecutive CLI successes and re-enables API attempts after the threshold, preventing permanent fallback while avoiding excessive API retry attempts.
366-373: Environment sanitization is a good practice.Filtering out
undefinedvalues fromprocess.envbefore passing to spawn prevents potential issues with some spawn implementations that don't handle undefined env values gracefully.
455-507: Well-structured proactive swap implementation.Good practices:
- Uses
Setfor efficient exclusion checking- Profiles are pre-sorted by availability
- Detailed event emissions for both success and failure cases
- Comment on line 505-506 correctly notes the intentional delay to prevent cascading swaps
| // Parse reset time strings into timestamps for countdown timer | ||
| const sessionResetTimestamp = usageData.sessionResetTime | ||
| ? parseResetTime(usageData.sessionResetTime).getTime() | ||
| : undefined; | ||
| const weeklyResetTimestamp = usageData.weeklyResetTime | ||
| ? parseResetTime(usageData.weeklyResetTime).getTime() | ||
| : undefined; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider graceful handling of individual reset time parsing failures.
If parseResetTime throws for one value (e.g., malformed session reset), the entire snapshot is discarded. You could wrap each call individually to preserve partial data.
♻️ Optional: Individual error handling
const sessionResetTimestamp = (() => {
try {
return usageData.sessionResetTime
? parseResetTime(usageData.sessionResetTime).getTime()
: undefined;
} catch { return undefined; }
})();
const weeklyResetTimestamp = (() => {
try {
return usageData.weeklyResetTime
? parseResetTime(usageData.weeklyResetTime).getTime()
: undefined;
} catch { return undefined; }
})();🤖 Prompt for AI Agents
In @apps/frontend/src/main/claude-profile/usage-monitor.ts around lines 406 -
413, Wrap each parseResetTime call separately so a thrown error for one reset
string doesn't discard the whole snapshot: when computing sessionResetTimestamp
and weeklyResetTimestamp from usageData.sessionResetTime and
usageData.weeklyResetTime, catch errors per-call (e.g., try/catch or small
self-invoking helper) and return undefined on failure so parseResetTime
exceptions only affect that timestamp and not the other fields or the overall
snapshot.
| if (!mainWindow.isDestroyed()) { | ||
| mainWindow.webContents.send(IPC_CHANNELS.USAGE_UPDATED, usage); | ||
| } | ||
| }); | ||
|
|
||
| // Forward proactive swap completed events to renderer | ||
| monitor.on('proactive-swap-completed', (data: any) => { | ||
| if (!mainWindow.isDestroyed()) { | ||
| mainWindow.webContents.send(IPC_CHANNELS.PROACTIVE_SWAP_NOTIFICATION, { | ||
| type: 'completed', | ||
| ...data | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| // Forward proactive swap notifications to renderer | ||
| // Forward proactive swap failed events to renderer | ||
| monitor.on('proactive-swap-failed', (data: any) => { | ||
| if (!mainWindow.isDestroyed()) { | ||
| mainWindow.webContents.send(IPC_CHANNELS.PROACTIVE_SWAP_NOTIFICATION, { | ||
| type: 'failed', | ||
| ...data | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| // Forward show-swap-notification events (for in-app swap notifications) | ||
| monitor.on('show-swap-notification', (notification: unknown) => { | ||
| mainWindow.webContents.send(IPC_CHANNELS.PROACTIVE_SWAP_NOTIFICATION, notification); | ||
| if (!mainWindow.isDestroyed()) { | ||
| mainWindow.webContents.send(IPC_CHANNELS.PROACTIVE_SWAP_NOTIFICATION, notification); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Good defensive guards, but consider typing the event data.
The mainWindow.isDestroyed() checks are a good safeguard against sending IPC messages to destroyed windows, preventing potential crashes.
However, the data: any parameter types on lines 770 and 780 could be replaced with proper interfaces for better type safety.
♻️ Optional: Add typed event payloads
// Define in shared types
interface ProactiveSwapCompletedData {
fromProfile: { id: string; name?: string };
toProfile: { id: string; name: string };
limitType: 'session' | 'weekly';
timestamp: Date;
}
interface ProactiveSwapFailedData {
reason: string;
currentProfile: string;
excludedProfiles: string[];
}Then use these types instead of any in the event handlers.
🤖 Prompt for AI Agents
In @apps/frontend/src/main/ipc-handlers/terminal-handlers.ts around lines 764 -
794, The handlers for monitor.on('proactive-swap-completed') and
monitor.on('proactive-swap-failed') use data: any — replace these with explicit
typed payloads (e.g., ProactiveSwapCompletedData and ProactiveSwapFailedData)
defined in a shared types file and import them into terminal-handlers.ts, then
update the event listener signatures to use those interfaces (and likewise type
the show-swap-notification parameter if you have a Notification type); keep the
existing mainWindow.isDestroyed() guards and ensure the typed payloads match the
IPC shape you send via IPC_CHANNELS.PROACTIVE_SWAP_NOTIFICATION.
Fixes PR review feedback about CLI invocation not using the correct profile environment. The fetchUsageViaCLI function now properly merges the augmented environment from getClaudeCliInvocationAsync with the profile-specific environment from getProfileEnv. This ensures the /usage command runs against the correct profile instead of the default context. Changes: - Import getProfileEnv from rate-limit-detector - Use both augmentedEnv and profileEnv in fetchUsageViaCLI - Merge environments with profile-specific vars taking precedence Refs: ACS-228, PR AndyMik90#975
The usage monitor was only starting when proactiveSwapEnabled was true, which meant the usage badge wouldn't show for users who didn't have proactive account switching enabled. Changes: - Remove early return in UsageMonitor.start() for proactiveSwapEnabled - Add check in checkUsageAndSwap() to only perform swaps when enabled - Usage monitor now always runs to fetch usage data for badge display - Proactive swapping only occurs when proactiveSwapEnabled is true This ensures the usage badge is always visible regardless of the proactive swap setting. Fixes issue where badge wasn't showing on top bar. Refs: ACS-228, PR AndyMik90#975
The usage badge wasn't showing because it relied on the UsageMonitor which might not have data when the component mounts. This adds an on-demand API that fetches usage immediately when the badge loads. Changes: - Add fetchActiveProfileUsage() function to profile-usage.ts - Add PROFILES_GET_USAGE IPC channel and handler - Add getAPIProfileUsage() to ProfileAPI and ElectronAPI interfaces - Update UsageIndicator to use getAPIProfileUsage() on mount - Add periodic 30-second refresh for usage data - Update browser-mock.ts with getAPIProfileUsage mock This matches the experimental/usage-statistics implementation. Refs: ACS-228, PR AndyMik90#975
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/frontend/src/main/ipc-handlers/terminal-handlers.ts (1)
785-822: Consider cleaning up event listeners when window is destroyed.The event listeners on the UsageMonitor singleton are never removed. If
mainWindowis destroyed and recreated (e.g., on macOS when app is reactivated), old listeners pointing to destroyed window references will accumulate. Consider usingmainWindow.on('closed', ...)to clean up listeners.♻️ Suggested approach
export function initializeUsageMonitorForwarding(mainWindow: BrowserWindow): void { const monitor = getUsageMonitor(); + const usageHandler = (usage: ClaudeUsageSnapshot) => { + if (!mainWindow.isDestroyed()) { + mainWindow.webContents.send(IPC_CHANNELS.USAGE_UPDATED, usage); + } + }; + + const swapCompletedHandler = (data: any) => { + if (!mainWindow.isDestroyed()) { + mainWindow.webContents.send(IPC_CHANNELS.PROACTIVE_SWAP_NOTIFICATION, { + type: 'completed', + ...data + }); + } + }; + + // ... similar for other handlers + + monitor.on('usage-updated', usageHandler); + monitor.on('proactive-swap-completed', swapCompletedHandler); + // ... other listeners + + // Cleanup listeners when window is closed + mainWindow.on('closed', () => { + monitor.off('usage-updated', usageHandler); + monitor.off('proactive-swap-completed', swapCompletedHandler); + // ... other cleanup + }); debugLog('[terminal-handlers] Usage monitor event forwarding initialized'); }
🤖 Fix all issues with AI agents
In @apps/frontend/src/main/claude-profile/usage-monitor.ts:
- Around line 402-407: The timeout handler currently calls proc.kill() (which
sends SIGTERM) causing possible delayed shutdown; update the timeout callback in
UsageMonitor where timeoutId/timedOut are set to call proc.kill('SIGKILL') to
force immediate termination (and keep the existing timedOut = true and
resolve(null) behavior); ensure the change targets the anonymous timeout
function that uses UsageMonitor.CLI_USAGE_TIMEOUT_MS so the process is
hard-killed on timeout.
- Around line 378-381: The cleanEnv creation filters out only undefined values
from mergedEnv, but nulls remain and may become the string "null" downstream;
update the filter used in
Object.fromEntries(Object.entries(mergedEnv).filter(...)) to exclude both
undefined and null (e.g., value !== undefined && value !== null) so cleanEnv
contains only real string values before it's used in spawn or other APIs.
In @apps/frontend/src/main/ipc-handlers/terminal-handlers.ts:
- Around line 796-802: Event handlers use untyped parameters; define interfaces
(e.g., ProactiveSwapCompletedPayload and ProactiveSwapFailedPayload) describing
the expected fields, then replace the any types in the monitor.on callbacks
(e.g., the handler registered for 'proactive-swap-completed' and the one for
'proactive-swap-failed') with the new interfaces; ensure the payload shapes
match what you spread into the IPC message and update imports/exports as needed
so TypeScript enforces the event payload shape.
In @apps/frontend/src/renderer/components/UsageIndicator.tsx:
- Around line 95-107: The periodic refresh ignores failures from
window.electronAPI.getAPIProfileUsage(); update the setInterval callback in
UsageIndicator to handle errors: add a .catch to the promise and handle
non-success responses (result.success === false) by logging the error (console
or existing logger) and updating component state to reflect an error (e.g.,
introduce setUsageError or setUsage(null) so the UI can show stale/errored state
or a toast). Ensure you still call setUsage(result.data) only on success, and
leave the unsubscribe() and clearInterval(intervalId) cleanup unchanged.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (9)
apps/frontend/src/main/claude-profile/usage-monitor.tsapps/frontend/src/main/ipc-handlers/terminal-handlers.tsapps/frontend/src/main/services/profile/index.tsapps/frontend/src/main/services/profile/profile-usage.tsapps/frontend/src/preload/api/profile-api.tsapps/frontend/src/renderer/components/UsageIndicator.tsxapps/frontend/src/renderer/lib/browser-mock.tsapps/frontend/src/shared/constants/ipc.tsapps/frontend/src/shared/types/ipc.ts
🧰 Additional context used
📓 Path-based instructions (2)
apps/frontend/src/**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
apps/frontend/src/**/*.{tsx,ts}: Use i18n translation keys for all user-facing text in the frontend. All labels, buttons, messages must use translation keys from react-i18next with namespace:section.key format (e.g., 'navigation:items.githubPRs').
Never use hardcoded strings for UI text in JSX/TSX files. Always use translation keys via useTranslation() hook.
Files:
apps/frontend/src/renderer/components/UsageIndicator.tsxapps/frontend/src/main/services/profile/index.tsapps/frontend/src/shared/constants/ipc.tsapps/frontend/src/preload/api/profile-api.tsapps/frontend/src/main/ipc-handlers/terminal-handlers.tsapps/frontend/src/main/services/profile/profile-usage.tsapps/frontend/src/shared/types/ipc.tsapps/frontend/src/renderer/lib/browser-mock.tsapps/frontend/src/main/claude-profile/usage-monitor.ts
apps/frontend/**/*.{ts,tsx}
⚙️ CodeRabbit configuration file
apps/frontend/**/*.{ts,tsx}: Review React patterns and TypeScript type safety.
Check for proper state management and component composition.
Files:
apps/frontend/src/renderer/components/UsageIndicator.tsxapps/frontend/src/main/services/profile/index.tsapps/frontend/src/shared/constants/ipc.tsapps/frontend/src/preload/api/profile-api.tsapps/frontend/src/main/ipc-handlers/terminal-handlers.tsapps/frontend/src/main/services/profile/profile-usage.tsapps/frontend/src/shared/types/ipc.tsapps/frontend/src/renderer/lib/browser-mock.tsapps/frontend/src/main/claude-profile/usage-monitor.ts
🧠 Learnings (4)
📓 Common learnings
Learnt from: MikeeBuilds
Repo: AndyMik90/Auto-Claude PR: 661
File: apps/frontend/src/renderer/components/onboarding/OllamaModelSelector.tsx:176-189
Timestamp: 2026-01-04T23:59:48.743Z
Learning: In the AndyMik90/Auto-Claude repository, pre-existing i18n issues (hardcoded user-facing strings that should be localized) can be deferred to future i18n cleanup passes rather than requiring immediate fixes in PRs that don't introduce new i18n violations.
📚 Learning: 2026-01-12T13:47:32.539Z
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T13:47:32.539Z
Learning: Applies to apps/frontend/src/**/*.{tsx,ts} : Use i18n translation keys for all user-facing text in the frontend. All labels, buttons, messages must use translation keys from react-i18next with namespace:section.key format (e.g., 'navigation:items.githubPRs').
Applied to files:
apps/frontend/src/renderer/components/UsageIndicator.tsxapps/frontend/src/main/services/profile/profile-usage.ts
📚 Learning: 2026-01-12T13:47:32.539Z
Learnt from: CR
Repo: AndyMik90/Auto-Claude PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-12T13:47:32.539Z
Learning: Applies to apps/frontend/src/**/*.{tsx,ts} : Never use hardcoded strings for UI text in JSX/TSX files. Always use translation keys via useTranslation() hook.
Applied to files:
apps/frontend/src/renderer/components/UsageIndicator.tsxapps/frontend/src/main/services/profile/profile-usage.ts
📚 Learning: 2026-01-04T23:59:45.209Z
Learnt from: MikeeBuilds
Repo: AndyMik90/Auto-Claude PR: 661
File: apps/frontend/src/renderer/components/onboarding/OllamaModelSelector.tsx:176-189
Timestamp: 2026-01-04T23:59:45.209Z
Learning: In the AndyMik90/Auto-Claude repository, pre-existing i18n issues (hardcoded user-facing strings) can be deferred for future i18n cleanup passes. Do not fix such issues in PRs that do not introduce new i18n violations, especially in frontend TSX components (e.g., apps/frontend/**/*.tsx). If a PR adds new i18n violations, address them in that PR.
Applied to files:
apps/frontend/src/renderer/components/UsageIndicator.tsx
🧬 Code graph analysis (4)
apps/frontend/src/renderer/components/UsageIndicator.tsx (2)
apps/frontend/src/shared/types/agent.ts (2)
ClaudeUsageSnapshot(42-65)RESETTING_SOON(14-14)apps/frontend/src/main/services/profile/index.ts (1)
RESETTING_SOON(57-57)
apps/frontend/src/preload/api/profile-api.ts (2)
apps/frontend/src/shared/types/agent.ts (1)
ClaudeUsageSnapshot(42-65)apps/frontend/src/__mocks__/electron.ts (1)
ipcRenderer(53-61)
apps/frontend/src/main/services/profile/profile-usage.ts (1)
apps/frontend/src/shared/types/agent.ts (2)
ClaudeUsageSnapshot(42-65)RESETTING_SOON(14-14)
apps/frontend/src/shared/types/ipc.ts (3)
apps/frontend/src/shared/types/task.ts (1)
ImageAttachment(117-125)apps/frontend/src/shared/types/terminal.ts (1)
TerminalWorktreeConfig(146-163)apps/frontend/src/shared/types/agent.ts (1)
ClaudeUsageSnapshot(42-65)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Seer Code Review
🔇 Additional comments (20)
apps/frontend/src/shared/types/ipc.ts (1)
45-46: LGTM!The new IPC type definitions are well-structured and properly typed:
ImageAttachmentimport andsubmitReviewsignature extension correctly support image attachments in reviews- New terminal event listeners (
onTerminalWorktreeConfigChange,onTerminalClaudeExit) align with the types interminal.tsgetAPIProfileUsagereturnsIPCResult<ClaudeUsageSnapshot>matching the usage service implementation- Claude Code CLI operations are consistently typed with the existing patterns
Also applies to: 162-162, 223-225, 244-245, 309-309, 598-598, 777-780
apps/frontend/src/shared/constants/ipc.ts (1)
91-91: LGTM!The new IPC channel constants follow the established naming conventions and align with the corresponding type definitions in
ipc.ts. The channel names are descriptive and consistent with the existing codebase patterns.Also applies to: 98-98, 135-135, 484-484, 512-515
apps/frontend/src/main/services/profile/profile-usage.ts (5)
1-14: Well-structured module with proper separation of concerns.The imports are clean and the module organization with clear section headers improves readability. Good use of the shared
RESETTING_SOONconstant for consistency across frontend and backend.
88-114: LGTM!Provider detection logic is sound:
- Proper URL parsing with error handling
- Correct domain matching for Z.ai (including subdomains)
- OAuth token identification via
sk-ant-oat01-prefix- Safe fallback to
'other'for invalid URLs or unknown providers
124-193: Z.ai usage fetching looks good with proper timeout and error handling.One observation on the
limitTypedetermination at line 181:limitType: tokenPercent > toolPercent ? 'session' : 'weekly',For Z.ai,
sessionPercentrepresents token usage andweeklyPercentrepresents tool/time usage. These are distinct quota types rather than the same metric over different time windows (unlike Anthropic's 5-hour vs 7-day). The comparison is technically valid for determining which limit is higher, but the semantic meaning differs from Anthropic's model.This appears intentional for UI consistency—flagging for verification that the downstream UI correctly interprets this for Z.ai.
208-278: LGTM!The Anthropic OAuth usage fetching is well-implemented:
- Proper AbortController timeout pattern
- Correct re-throwing of
ApiAuthErrorfor auth failures- Bounds validation on percentages with
Math.max(0, Math.min(100, ...))- Appropriate
anthropic-versionheader included
334-381: LGTM!The
fetchActiveProfileUsagefunction properly orchestrates the usage fetching flow with appropriate error handling and structured result types.apps/frontend/src/renderer/components/UsageIndicator.tsx (4)
9-11: Good i18n setup and imports.The
useTranslation('navigation')hook andRESETTING_SOONimport are correctly configured. All user-facing text properly uses translation keys as per coding guidelines.Also applies to: 19-19, 22-22
28-77: Well-implemented countdown logic.The
calculateCountdownandformatResetTimecallbacks are correctly memoized withuseCallback. The per-second interval for countdown updates is properly cleaned up and only runs when usage is at 99% or higher—avoiding unnecessary timers.
129-132: Provider-specific labels and tooltip content are correctly internationalized.All labels use appropriate i18n keys with the
namespace:section.keyformat:
usageIndicator.tokenUsage/usageIndicator.sessionUsagefor session labelusageIndicator.monthlyToolUsage/usageIndicator.weeklyUsagefor weekly labelusageIndicator.resets,usageIndicator.activeAccount,usageIndicator.ariaLabelThis follows the coding guidelines for frontend i18n compliance.
Also applies to: 160-170, 187-196, 214-218
143-155: Nice UX touch with the pulsing clock icon for high usage states.The conditional rendering of
Clockwithanimate-pulsewhen countdown is active provides clear visual feedback. The countdown text display alongside the percentage is well-integrated.apps/frontend/src/main/services/profile/index.ts (1)
34-57: LGTM!The barrel exports are well-organized and follow the existing patterns in the file. Re-exporting
RESETTING_SOONfrom the shared types provides convenient access for consumers of the profile service module.apps/frontend/src/main/claude-profile/usage-monitor.ts (3)
34-40: LGTM on swap loop protection and retry mechanism.The auth failure cooldown tracking and CLI fallback retry threshold are good additions to prevent swap loops and gracefully recover API access after temporary failures.
114-220: LGTM on checkUsageAndSwap logic.The concurrent check prevention, provider-specific swap logic, and auth failure tracking with cooldown cleanup are well-implemented. The
isCheckingflag infinallyensures proper state reset even on exceptions.
467-519: LGTM on proactive swap logic.Good use of Set for deduplication, proper exclusion handling for auth-failed profiles, and the deliberate decision to not immediately check the new profile to prevent cascading swaps is well-documented.
apps/frontend/src/preload/api/profile-api.ts (1)
33-34: LGTM on getAPIProfileUsage addition.The new method follows the established IPC pattern in this file and correctly types the return value as
IPCResult<ClaudeUsageSnapshot>.Also applies to: 79-81
apps/frontend/src/main/ipc-handlers/terminal-handlers.ts (2)
55-72: LGTM on async settings read wrapper.Wrapping the Claude invocation in an async IIFE to avoid blocking the main process during settings read is the right approach. The error is properly caught and logged.
610-633: LGTM on PROFILES_GET_USAGE handler.The handler correctly validates both
result.successandresult.usagebefore returning, with appropriate error fallback messages. The dynamic import pattern for the profile service is consistent with the codebase.apps/frontend/src/renderer/lib/browser-mock.ts (2)
149-164: LGTM on getAPIProfileUsage mock.The mock provides reasonable default values for browser testing. The structure aligns with the
ClaudeUsageSnapshottype fromapps/frontend/src/shared/types/agent.ts.
270-297: LGTM on Claude Code management mocks.The new mocks for
getClaudeCodeVersions,installClaudeCodeVersion,getClaudeCodeInstallations, andsetClaudeCodeActivePathprovide sensible default data for browser-based UI development and testing.
| // Remove undefined values | ||
| const cleanEnv = Object.fromEntries( | ||
| Object.entries(mergedEnv).filter(([_, value]) => value !== undefined) | ||
| ) as Record<string, string>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider also filtering null values from environment.
The filter removes undefined but not null. While env vars should typically be strings, null values would be stringified to "null" by the spawn API, which could cause unexpected behavior.
♻️ Suggested change
// Remove undefined values
const cleanEnv = Object.fromEntries(
- Object.entries(mergedEnv).filter(([_, value]) => value !== undefined)
+ Object.entries(mergedEnv).filter(([_, value]) => value != null)
) as Record<string, string>;📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Remove undefined values | |
| const cleanEnv = Object.fromEntries( | |
| Object.entries(mergedEnv).filter(([_, value]) => value !== undefined) | |
| ) as Record<string, string>; | |
| // Remove undefined values | |
| const cleanEnv = Object.fromEntries( | |
| Object.entries(mergedEnv).filter(([_, value]) => value != null) | |
| ) as Record<string, string>; |
🤖 Prompt for AI Agents
In @apps/frontend/src/main/claude-profile/usage-monitor.ts around lines 378 -
381, The cleanEnv creation filters out only undefined values from mergedEnv, but
nulls remain and may become the string "null" downstream; update the filter used
in Object.fromEntries(Object.entries(mergedEnv).filter(...)) to exclude both
undefined and null (e.g., value !== undefined && value !== null) so cleanEnv
contains only real string values before it's used in spawn or other APIs.
| monitor.on('proactive-swap-completed', (data: any) => { | ||
| if (!mainWindow.isDestroyed()) { | ||
| mainWindow.webContents.send(IPC_CHANNELS.PROACTIVE_SWAP_NOTIFICATION, { | ||
| type: 'completed', | ||
| ...data | ||
| }); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider typing event data parameters.
The data: any parameters in the event handlers could be typed for better maintainability. Consider defining interfaces for swap completion/failure event payloads.
Also applies to: 806-812
🤖 Prompt for AI Agents
In @apps/frontend/src/main/ipc-handlers/terminal-handlers.ts around lines 796 -
802, Event handlers use untyped parameters; define interfaces (e.g.,
ProactiveSwapCompletedPayload and ProactiveSwapFailedPayload) describing the
expected fields, then replace the any types in the monitor.on callbacks (e.g.,
the handler registered for 'proactive-swap-completed' and the one for
'proactive-swap-failed') with the new interfaces; ensure the payload shapes
match what you spread into the IPC message and update imports/exports as needed
so TypeScript enforces the event payload shape.
| // Set up interval to refresh usage every 30 seconds | ||
| const intervalId = setInterval(() => { | ||
| window.electronAPI.getAPIProfileUsage().then((result) => { | ||
| if (result.success && result.data) { | ||
| setUsage(result.data); | ||
| } | ||
| }); | ||
| }, 30000); // 30 seconds | ||
|
|
||
| return () => { | ||
| unsubscribe(); | ||
| clearInterval(intervalId); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧹 Nitpick | 🔵 Trivial
Consider handling errors in the periodic refresh.
The 30-second refresh interval silently ignores failures. If getAPIProfileUsage() starts failing (e.g., network issues, auth expiry), the user sees stale data without indication.
Optional: Add error handling for refresh failures
// Set up interval to refresh usage every 30 seconds
const intervalId = setInterval(() => {
window.electronAPI.getAPIProfileUsage().then((result) => {
if (result.success && result.data) {
setUsage(result.data);
+ } else if (!result.success) {
+ // Optionally hide stale data or show error state
+ // setIsVisible(false);
+ console.warn('[UsageIndicator] Refresh failed:', result.error);
}
});
}, 30000); // 30 seconds📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // Set up interval to refresh usage every 30 seconds | |
| const intervalId = setInterval(() => { | |
| window.electronAPI.getAPIProfileUsage().then((result) => { | |
| if (result.success && result.data) { | |
| setUsage(result.data); | |
| } | |
| }); | |
| }, 30000); // 30 seconds | |
| return () => { | |
| unsubscribe(); | |
| clearInterval(intervalId); | |
| }; | |
| // Set up interval to refresh usage every 30 seconds | |
| const intervalId = setInterval(() => { | |
| window.electronAPI.getAPIProfileUsage().then((result) => { | |
| if (result.success && result.data) { | |
| setUsage(result.data); | |
| } else if (!result.success) { | |
| // Optionally hide stale data or show error state | |
| // setIsVisible(false); | |
| console.warn('[UsageIndicator] Refresh failed:', result.error); | |
| } | |
| }); | |
| }, 30000); // 30 seconds | |
| return () => { | |
| unsubscribe(); | |
| clearInterval(intervalId); | |
| }; |
🤖 Prompt for AI Agents
In @apps/frontend/src/renderer/components/UsageIndicator.tsx around lines 95 -
107, The periodic refresh ignores failures from
window.electronAPI.getAPIProfileUsage(); update the setInterval callback in
UsageIndicator to handle errors: add a .catch to the promise and handle
non-success responses (result.success === false) by logging the error (console
or existing logger) and updating component state to reflect an error (e.g.,
introduce setUsageError or setUsage(null) so the UI can show stale/errored state
or a toast). Ensure you still call setUsage(result.data) only on success, and
leave the unsubscribe() and clearInterval(intervalId) cleanup unchanged.
# Conflicts: # apps/frontend/src/main/claude-profile/usage-monitor.ts
| import { spawn } from 'child_process'; | ||
| import { getClaudeProfileManager } from '../claude-profile-manager'; | ||
| import { ClaudeUsageSnapshot } from '../../shared/types/agent'; | ||
| import { loadProfilesFile, detectProvider, fetchUsageForProfile, fetchAnthropicOAuthUsage } from '../services/profile'; |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note
| import { loadProfilesFile, detectProvider, fetchUsageForProfile, fetchAnthropicOAuthUsage } from '../services/profile'; | ||
| import { getClaudeCliInvocationAsync } from '../claude-cli-utils'; | ||
| import { getSpawnCommand, getSpawnOptions } from '../env-utils'; | ||
| import { parseUsageOutput, parseResetTime, classifyRateLimitType } from './usage-parser'; |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note
| export async function fetchActiveProfileUsage(): Promise<UsageFetchResult> { | ||
| try { | ||
| const file = await loadProfilesFile(); | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bug: fetchActiveProfileUsage doesn't check for OAuth profiles, causing the usage badge to fail on initial load for OAuth users.
Severity: MEDIUM
Suggested Fix
Modify fetchActiveProfileUsage to also check for an active OAuth profile, likely via ClaudeProfileManager, when no active API key profile is found. This will ensure usage data is fetched immediately on load for both authentication methods.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent.
Verify if this is a real issue. If it is, propose a fix; if not, explain why it's not
valid.
Location: apps/frontend/src/main/services/profile/profile-usage.ts#L334-L337
Potential issue: The `fetchActiveProfileUsage` function is intended to support both
OAuth and API key profiles, as indicated by code comments. However, its implementation
only checks for an active profile in the API profiles file via `loadProfilesFile()`. It
does not check for active OAuth profiles managed by `ClaudeProfileManager`.
Consequently, for OAuth users, `file.activeProfileId` will be `null` on initial load,
causing the function to return an error. This prevents the usage badge from being
displayed until the `UsageMonitor` provides an update, which can be delayed by up to 30
seconds.
Did we get this right? 👍 / 👎 to inform future reviews.
|
Branch diversion, will recreate PR |
Base Branch
Description
Implements a real-time usage statistics badge in the top navigation bar that displays current Claude API usage with color-coded status indicators and countdown timer functionality.
Key features:
Related Issue
Closes #ACS-228
Type of Change
Area
Commit Message Format
Follow conventional commits: `: `
Types: feat, fix, docs, style, refactor, test
Example: `feat: add user authentication system`
Checklist
CI/Testing Requirements
Screenshots
Feature Toggle
Breaking Changes
Breaking: No
Details: No breaking changes. The feature is additive and does not modify existing behavior.
Summary by CodeRabbit
New Features
Accessibility
Internationalization
Tests
Bug Fixes
Chores
✏️ Tip: You can customize this high-level summary in your review settings.