Skip to content

Conversation

@VDT-91
Copy link

@VDT-91 VDT-91 commented Jan 8, 2026

Summary

  • Fixes race condition where version check runs before settings load, causing Claude CLI to show "not found" initially
  • Suppresses expected "node is not recognized" error on Windows with nvm-windows + GUI launch
  • Claude CLI now detects correctly immediately on startup without requiring manual refresh

Problem

When Auto Claude starts from Windows GUI (Start Menu, desktop shortcut) - not terminal:

  1. Race condition: CLAUDE_CODE_CHECK_VERSION IPC called before user settings load, so getToolInfo('claude') did fresh detection ignoring user config
  2. npm.cmd failure: With nvm-windows, node isn't in PATH when launched from GUI, causing npm.cmd config get prefix to fail with "node is not recognized"

Solution

Change 1: Make getToolInfo() respect user configuration

  • Added getUserConfiguredPath() helper to extract user-configured paths
  • Added validateToolByType() helper to validate paths by tool type
  • Updated getToolInfo() to check user config FIRST before fresh detection

Change 2: Suppress expected Windows error

  • Added check in getNpmGlobalPrefixAsync() to detect expected "is not recognized" error on Windows
  • Only logs error if it's NOT the expected nvm-windows issue

Files Changed

File Change
apps/frontend/src/main/cli-tool-manager.ts Added helpers, updated getToolInfo()
apps/frontend/src/main/env-utils.ts Suppressed expected Windows error

Test Plan

  • Verified fix works with npm start from terminal
  • Test Windows GUI launch (Start Menu/desktop shortcut)
  • Verify no regression on macOS/Linux

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Much improved Claude CLI detection on Windows: broader install sources supported (official installer, npm, local bin, Scoop, Chocolatey, Program Files, nvm-windows) and refined detection order.
    • Added Windows Registry PATH discovery (sync + async) with PATH parsing and env-var expansion.
    • Enhanced environment/path augmentation and command spawning for better Windows compatibility.
  • Tests

    • Updated test scaffolding to mock Windows registry and env-var behaviors for reliable Windows-related tests.

✏️ Tip: You can customize this high-level summary in your review settings.

AndyMik90 and others added 30 commits December 22, 2025 20:20
- Add comprehensive branching strategy documentation
- Explain main, develop, feature, fix, release, and hotfix branches
- Clarify that all PRs should target develop (not main)
- Add release process documentation for maintainers
- Update PR process to branch from develop
- Expand table of contents with new sections
* refactor: restructure project to Apps/frontend and Apps/backend

- Move auto-claude-ui to Apps/frontend with feature-based architecture
- Move auto-claude to Apps/backend
- Switch from pnpm to npm for frontend
- Update Node.js requirement to v24.12.0 LTS
- Add pre-commit hooks for lint, typecheck, and security audit
- Add commit-msg hook for conventional commits
- Fix CommonJS compatibility issues (postcss.config, postinstall scripts)
- Update README with comprehensive setup and contribution guidelines
- Configure ESLint to ignore .cjs files
- 0 npm vulnerabilities

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* feat(refactor): clean code and move to npm

* feat(refactor): clean code and move to npm

* chore: update to v2.7.0, remove Docker deps (LadybugDB is embedded)

* feat: v2.8.0 - update workflows and configs for Apps/ structure, npm

* fix: resolve Python lint errors (F401, I001)

* fix: update test paths for Apps/backend structure

* fix: add missing facade files and update paths for Apps/backend structure

- Fix ruff lint error I001 in auto_claude_tools.py
- Create missing facade files to match upstream (agent, ci_discovery, critique, etc.)
- Update test paths from auto-claude/ to Apps/backend/
- Update .pre-commit-config.yaml paths for Apps/ structure
- Add pytest to pre-commit hooks (skip slow/integration/Windows-incompatible tests)
- Fix Unicode encoding in test_agent_architecture.py for Windows

Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>

* feat: improve readme

* fix: new path

* fix: correct release workflow and docs for Apps/ restructure

- Fix ARM64 macOS build: pnpm → npm, auto-claude-ui → Apps/frontend
- Fix artifact upload paths in release.yml
- Update Node.js version to 24 for consistency
- Update CLI-USAGE.md with Apps/backend paths
- Update RELEASE.md with Apps/frontend/package.json paths

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* refactor: rename Apps/ to apps/ and fix backend path resolution

- Rename Apps/ folder to apps/ for consistency with JS/Node conventions
- Update all path references across CI/CD workflows, docs, and config files
- Fix frontend Python path resolver to look for 'backend' instead of 'auto-claude'
- Update path-resolver.ts to correctly find apps/backend in development mode

This completes the Apps restructure from PR AndyMik90#122 and prepares for v2.8.0 release.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(electron): correct preload script path from .js to .mjs

electron-vite builds the preload script as ESM (index.mjs) but the main
process was looking for CommonJS (index.js). This caused the preload to
fail silently, making the app fall back to browser mock mode with fake
data and non-functional IPC handlers.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* - Introduced `dev:debug` script to enable debugging during development.
- Added `dev:mcp` script for running the frontend in MCP mode.

These enhancements streamline the development process for frontend developers.

* refactor(memory): make Graphiti memory mandatory and remove Docker dependency

Memory is now a core component of Auto Claude rather than optional:
- Python 3.12+ is required for the backend (not just memory layer)
- Graphiti is enabled by default in .env.example
- Removed all FalkorDB/Docker references (migrated to embedded LadybugDB)
- Deleted guides/DOCKER-SETUP.md and docker-handlers.ts
- Updated onboarding UI to remove "optional" language
- Updated all documentation to reflect LadybugDB architecture

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: add cross-platform Windows support for npm scripts

- Add scripts/install-backend.js for cross-platform Python venv setup
  - Auto-detects Python 3.12 (py -3.12 on Windows, python3.12 on Unix)
  - Handles platform-specific venv paths
- Add scripts/test-backend.js for cross-platform pytest execution
- Update package.json to use Node.js scripts instead of shell commands
- Update CONTRIBUTING.md with correct paths and instructions:
  - apps/backend/ and apps/frontend/ paths
  - Python 3.12 requirement (memory system now required)
  - Platform-specific install commands (winget, brew, apt)
  - npm instead of pnpm
  - Quick Start section with npm run install:all

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* remove doc

* fix(frontend): correct Ollama detector script path after apps restructure

The Ollama status check was failing because memory-handlers.ts
was looking for ollama_model_detector.py at auto-claude/ but the
script is now at apps/backend/ after the directory restructure.

This caused "Ollama not running" to display even when Ollama was
actually running and accessible.

* chore: bump version to 2.7.2

Downgrade version from 2.8.0 to 2.7.2 as the Apps/ restructure
is better suited as a patch release rather than a minor release.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* chore: update package-lock.json for Windows compatibility

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* docs(contributing): add hotfix workflow and update paths for apps/ structure

Add Git Flow hotfix workflow documentation with step-by-step guide
and ASCII diagram showing the branching strategy.

Update all paths from auto-claude/auto-claude-ui to apps/backend/apps/frontend
and migrate package manager references from pnpm to npm to match the
new project structure.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ci): remove duplicate ARM64 build from Intel runner

The Intel runner was building both x64 and arm64 architectures,
while a separate ARM64 runner also builds arm64 natively. This
caused duplicate ARM64 builds, wasting CI resources.

Now each runner builds only its native architecture:
- Intel runner: x64 only
- ARM64 runner: arm64 only

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: Alex Madera <[email protected]>
Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.5 <[email protected]>
…Mik90#141)

* feat(ollama): add real-time download progress tracking for model downloads

Implement comprehensive download progress tracking with:
- NDJSON parsing for streaming progress data from Ollama API
- Real-time speed calculation (MB/s, KB/s, B/s) with useRef for delta tracking
- Time remaining estimation based on download speed
- Animated progress bars in OllamaModelSelector component
- IPC event streaming from main process to renderer
- Proper listener management with cleanup functions

Changes:
- memory-handlers.ts: Parse NDJSON from Ollama stderr, emit progress events
- OllamaModelSelector.tsx: Display progress bars with speed and time remaining
- project-api.ts: Implement onDownloadProgress listener with cleanup
- ipc.ts types: Define onDownloadProgress listener interface
- infrastructure-mock.ts: Add mock implementation for browser testing

This allows users to see real-time feedback when downloading Ollama models,
including percentage complete, current download speed, and estimated time remaining.

* test: add focused test coverage for Ollama download progress feature

Add unit tests for the critical paths of the real-time download progress tracking:

- Progress calculation tests (52 tests): Speed/time/percentage calculations with comprehensive edge case coverage (zero speeds, NaN, Infinity, large numbers)
- NDJSON parser tests (33 tests): Streaming JSON parsing from Ollama, buffer management for incomplete lines, error handling

All 562 unit tests passing with clean dependencies. Tests focus on critical mathematical logic and data processing - the most important paths that need verification.

Test coverage:
✅ Speed calculation and formatting (B/s, KB/s, MB/s)
✅ Time remaining calculations (seconds, minutes, hours)
✅ Percentage clamping (0-100%)
✅ NDJSON streaming with partial line buffering
✅ Invalid JSON handling
✅ Real Ollama API responses
✅ Multi-chunk streaming scenarios

* docs: add comprehensive JSDoc docstrings for Ollama download progress feature

- Enhanced OllamaModelSelector component with detailed JSDoc
  * Documented component props, behavior, and usage examples
  * Added docstrings to internal functions (checkInstalledModels, handleDownload, handleSelect)
  * Explained progress tracking algorithm and useRef usage

- Improved memory-handlers.ts documentation
  * Added docstring to main registerMemoryHandlers function
  * Documented all Ollama-related IPC handlers (check-status, list-embedding-models, pull-model)
  * Added JSDoc to executeOllamaDetector helper function
  * Documented interface types (OllamaStatus, OllamaModel, OllamaEmbeddingModel, OllamaPullResult)
  * Explained NDJSON parsing and progress event structure

- Enhanced test file documentation
  * Added docstrings to NDJSON parser test utilities with algorithm explanation
  * Documented all calculation functions (speed, time, percentage)
  * Added detailed comments on formatting and bounds-checking logic

- Improved overall code maintainability
  * Docstring coverage now meets 80%+ threshold for code review
  * Clear explanation of progress tracking implementation details
  * Better context for future maintainers working with download streaming

* feat: add batch task creation and management CLI commands

- Handle batch task creation from JSON files
- Show status of all specs in project
- Cleanup tool for completed specs
- Full integration with new apps/backend structure
- Compatible with implementation_plan.json workflow

* test: add batch task test file and testing checklist

- batch_test.json: Sample tasks for testing batch creation
- TESTING_CHECKLIST.md: Comprehensive testing guide for Ollama and batch tasks
- Includes UI testing steps, CLI testing steps, and edge cases
- Ready for manual and automated testing

* chore: update package-lock.json to match v2.7.2

* test: update checklist with verification results and architecture validation

* docs: add comprehensive implementation summary for Ollama + Batch features

* docs: add comprehensive Phase 2 testing guide with checklists and procedures

* docs: add NEXT_STEPS guide for Phase 2 testing

* fix: resolve merge conflict in project-api.ts from Ollama feature cherry-pick

* fix: remove duplicate Ollama check status handler registration

* test: update checklist with Phase 2 bug findings and fixes

---------

Co-authored-by: ray <[email protected]>
Implemented promise queue pattern in PythonEnvManager to handle
concurrent initialization requests. Previously, multiple simultaneous
requests (e.g., startup + merge) would fail with "Already
initializing" error.

Also fixed parsePythonCommand() to handle file paths with spaces by
checking file existence before splitting on whitespace.

Changes:
- Added initializationPromise field to queue concurrent requests
- Split initialize() into public and private _doInitialize()
- Enhanced parsePythonCommand() with existsSync() check

Co-authored-by: Joris Slagter <[email protected]>
)

Removes the legacy 'auto-claude' path from the possiblePaths array
in agent-process.ts. This path was from before the monorepo
restructure (v2.7.2) and is no longer needed.

The legacy path was causing spec_runner.py to be looked up at the
wrong location:
- OLD (wrong): /path/to/auto-claude/auto-claude/runners/spec_runner.py
- NEW (correct): /path/to/apps/backend/runners/spec_runner.py

This aligns with the new monorepo structure where all backend code
lives in apps/backend/.

Fixes AndyMik90#147

Co-authored-by: Joris Slagter <[email protected]>
* fix: Linear API authentication and GraphQL types

- Remove Bearer prefix from Authorization header (Linear API keys are sent directly)
- Change GraphQL variable types from String! to ID! for teamId and issue IDs
- Improve error handling to show detailed Linear API error messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: Radix Select empty value error in Linear import modal

Use '__all__' sentinel value instead of empty string for "All projects"
option, as Radix Select does not allow empty string values.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat: add CodeRabbit configuration file

Introduce a new .coderabbit.yaml file to configure CodeRabbit settings, including review profiles, automatic review options, path filters, and specific instructions for different file types. This enhances the code review process by providing tailored guidelines for Python, TypeScript, and test files.

* fix: correct GraphQL types for Linear team queries

Linear API uses different types for different queries:
- team(id:) expects String!
- issues(filter: { team: { id: { eq: } } }) expects ID!

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: refresh task list after Linear import

Call loadTasks() after successful Linear import to update the kanban
board without requiring a page reload.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* cleanup

* cleanup

* fix: address CodeRabbit review comments for Linear integration

- Fix unsafe JSON parsing: check response.ok before parsing JSON to handle
  non-JSON error responses (e.g., 503 from proxy) gracefully
- Use ID! type instead of String! for teamId in LINEAR_GET_PROJECTS query
  for GraphQL type consistency
- Remove debug console.log (ESLint config only allows warn/error)
- Refresh task list on partial import success (imported > 0) instead of
  requiring full success
- Fix pre-existing TypeScript and lint issues blocking commit

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* version sync logic

* lints for develop branch

* chore: update CI workflow to include develop branch

- Modified the CI configuration to trigger on pushes and pull requests to both main and develop branches, enhancing the workflow for development and integration processes.

* fix: update project directory auto-detection for apps/backend structure

The project directory auto-detection was checking for the old `auto-claude/`
directory name but needed to check for `apps/backend/`. When running from
`apps/backend/`, the directory name is `backend` not `auto-claude`, so the
check would fail and `project_dir` would incorrectly remain as `apps/backend/`
instead of resolving to the project root (2 levels up).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: use GraphQL variables instead of string interpolation in LINEAR_GET_ISSUES

Replace direct string interpolation of teamId and linearProjectId with
proper GraphQL variables. This prevents potential query syntax errors if
IDs contain special characters like double quotes, and aligns with the
variable-based approach used elsewhere in the file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ui): correct logging level and await loadTasks on import complete

- Change console.warn to console.log for import success messages
  (warn is incorrect severity for normal completion)
- Make onImportComplete callback async and await loadTasks()
  to prevent potential unhandled promise rejections

Applies CodeRabbit review feedback across 3 LinearTaskImportModal usages.

* fix(hooks): use POSIX-compliant find instead of bash glob

The pre-commit hook uses #!/bin/sh but had bash-specific ** glob
pattern for staging ruff-formatted files. The ** pattern only works
in bash with globstar enabled - in POSIX sh it expands literally
and won't match subdirectories, causing formatted files in nested
directories to not be staged.

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
…_progress

When a user drags a running task back to Planning (or any other column),
the process was not being stopped, leaving a "ghost" process that
prevented deletion with "Cannot delete a running task" error.

Now the task process is automatically killed when status changes away
from in_progress, ensuring the process state stays in sync with the UI.
* feat: add UI scale feature

* refactor: extract UI scale bounds to shared constants

* fix: duplicated import
…90#154)

* fix: analyzer Python compatibility and settings integration

Fixes project index analyzer failing with TypeError on Python type hints.

Changes:
- Added 'from __future__ import annotations' to all analysis modules
- Fixed project discovery to support new analyzer JSON format
- Read Python path directly from settings.json instead of pythonEnvManager
- Added stderr/stdout logging for analyzer debugging

Resolves 'Discovered 0 files' and 'TypeError: unsupported operand type' issues.

* auto-claude: subtask-1-1 - Hide status badge when execution phase badge is showing

When a task has an active execution (planning, coding, etc.), the
execution phase badge already displays the correct state with a spinner.
The status badge was also rendering, causing duplicate/confusing badges
(e.g., both "Planning" and "Pending" showing at the same time).

This fix wraps the status badge in a conditional that only renders when
there's no active execution, eliminating the redundant badge display.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(ipc): remove unused pythonEnvManager parameter and fix ES6 import

Address CodeRabbit review feedback:
- Remove unused pythonEnvManager parameter from registerProjectContextHandlers
  and registerContextHandlers (the code reads Python path directly from
  settings.json instead)
- Replace require('electron').app with proper ES6 import for consistency

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* chore(lint): fix import sorting in analysis module

Run ruff --fix to resolve I001 lint errors after merging develop.
All 23 files in apps/backend/analysis/ now have properly sorted imports.

---------

Co-authored-by: Joris Slagter <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
* fix(core): add task persistence, terminal handling, and HTTP 300 fixes

Consolidated bug fixes from PRs AndyMik90#168, AndyMik90#170, AndyMik90#171:

- Task persistence (AndyMik90#168): Scan worktrees for tasks on app restart
  to prevent loss of in-progress work and wasted API credits. Tasks
  in .worktrees/*/specs are now loaded and deduplicated with main.

- Terminal buttons (AndyMik90#170): Fix "Open Terminal" buttons silently
  failing on macOS by properly awaiting createTerminal() Promise.
  Added useTerminalHandler hook with loading states and error display.

- HTTP 300 errors (AndyMik90#171): Handle branch/tag name collisions that
  cause update failures. Added validation script to prevent conflicts
  before releases and user-friendly error messages with manual
  download links.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(platform): add path resolution, spaces handling, and XDG support

This commit consolidates multiple bug fixes from community PRs:

- PR AndyMik90#187: Path resolution fix - Update path detection to find apps/backend
  instead of legacy auto-claude directory after v2.7.2 restructure

- PR AndyMik90#182/AndyMik90#155: Python path spaces fix - Improve parsePythonCommand() to
  handle quoted paths and paths containing spaces without splitting

- PR AndyMik90#161: Ollama detection fix - Add new apps structure paths for
  ollama_model_detector.py script discovery

- PR AndyMik90#160: AppImage support - Add XDG Base Directory compliant paths for
  Linux sandboxed environments (AppImage, Flatpak, Snap). New files:
  - config-paths.ts: XDG path utilities
  - fs-utils.ts: Filesystem utilities with fallback support

- PR AndyMik90#159: gh CLI PATH fix - Add getAugmentedEnv() utility to include
  common binary locations (Homebrew, snap, local) in PATH for child
  processes. Fixes gh CLI not found when app launched from Finder/Dock.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address CodeRabbit/Cursor review comments on PR AndyMik90#185

Fixes from code review:
- http-client.ts: Use GITHUB_CONFIG instead of hardcoded owner in HTTP 300 error message
- validate-release.js: Fix substring matching bug in branch detection that could cause false positives (e.g., v2.7 matching v2.7.2)
- bump-version.js: Remove unnecessary try-catch wrapper (exec() already exits on failure)
- execution-handlers.ts: Capture original subtask status before mutation for accurate logging
- fs-utils.ts: Add error handling to safeWriteFile with proper logging

Dismissed as trivial/not applicable:
- config-paths.ts: Exhaustive switch check (over-engineering)
- env-utils.ts: PATH priority documentation (existing comments sufficient)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address additional CodeRabbit review comments (round 2)

Fixes from second round of code review:
- fs-utils.ts: Wrap test file cleanup in try-catch for Windows file locking
- fs-utils.ts: Add error handling to safeReadFile for consistency with safeWriteFile
- http-client.ts: Use GITHUB_CONFIG in fetchJson (missed in first round)
- validate-release.js: Exclude symbolic refs (origin/HEAD -> origin/main) from branch check
- python-detector.ts: Return cleanPath instead of pythonPath for empty input edge case

Dismissed as trivial/not applicable:
- execution-handlers.ts: Redundant checkSubtasksCompletion call (micro-optimization)

🤖 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]>
* chore: update README version to 2.7.1

Updated the version badge and download links in the README to reflect the new release version 2.7.1, ensuring users have the correct information for downloading the latest builds.

* feat(releases): add beta release system with user opt-in

Implements a complete beta release workflow that allows users to opt-in
to receiving pre-release versions. This enables testing new features
before they're included in stable releases.

Changes:
- Add beta-release.yml workflow for creating beta releases from develop
- Add betaUpdates setting with UI toggle in Settings > Updates
- Add update channel support to electron-updater (beta vs latest)
- Extract shared settings-utils.ts to reduce code duplication
- Add prepare-release.yml workflow for automated release preparation
- Document beta release process in CONTRIBUTING.md and RELEASE.md

Users can enable beta updates in Settings > Updates, and maintainers
can trigger beta releases via the GitHub Actions workflow.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* workflow update

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
* chore: update README version to 2.7.1

Updated the version badge and download links in the README to reflect the new release version 2.7.1, ensuring users have the correct information for downloading the latest builds.

* feat(releases): add beta release system with user opt-in

Implements a complete beta release workflow that allows users to opt-in
to receiving pre-release versions. This enables testing new features
before they're included in stable releases.

Changes:
- Add beta-release.yml workflow for creating beta releases from develop
- Add betaUpdates setting with UI toggle in Settings > Updates
- Add update channel support to electron-updater (beta vs latest)
- Extract shared settings-utils.ts to reduce code duplication
- Add prepare-release.yml workflow for automated release preparation
- Document beta release process in CONTRIBUTING.md and RELEASE.md

Users can enable beta updates in Settings > Updates, and maintainers
can trigger beta releases via the GitHub Actions workflow.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* workflow update

* ci(github): update Discord link and redirect feature requests to discussions

Update Discord invite link to correct URL (QhRnz9m5HE) across all GitHub
templates and workflows. Redirect feature requests from issue template
to GitHub Discussions for better community engagement.

Changes:
- config.yml: Add feature request link to Discussions, fix Discord URL
- question.yml: Update Discord link in pre-question guidance
- welcome.yml: Update Discord link in first-time contributor message

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
- Change branch reference from main to develop
- Fix contribution guide link to use full URL
- Remove hyphen from "Auto Claude" in welcome message
…tup (AndyMik90#180 AndyMik90#167) (AndyMik90#208)

This fixes critical bug where macOS users with default Python 3.9.6 couldn't use Auto-Claude because claude-agent-sdk requires Python 3.10+.

Root Cause:
- Auto-Claude doesn't bundle Python, relies on system Python
- python-detector.ts accepted any Python 3.x without checking minimum version
- macOS ships with Python 3.9.6 by default (incompatible)
- GitHub Actions runners didn't explicitly set Python version

Changes:
1. python-detector.ts:
   - Added getPythonVersion() to extract version from command
   - Added validatePythonVersion() to check if >= 3.10.0
   - Updated findPythonCommand() to skip Python < 3.10 with clear error messages

2. python-env-manager.ts:
   - Import and use findPythonCommand() (already has version validation)
   - Simplified findSystemPython() to use shared validation logic
   - Updated error message from "Python 3.9+" to "Python 3.10+" with download link

3. .github/workflows/release.yml:
   - Added Python 3.11 setup to all 4 build jobs (macOS Intel, macOS ARM64, Windows, Linux)
   - Ensures consistent Python version across all platforms during build

Impact:
- macOS users with Python 3.9 now see clear error with download link
- macOS users with Python 3.10+ work normally
- CI/CD builds use consistent Python 3.11
- Prevents "ModuleNotFoundError: dotenv" and dependency install failures

Fixes AndyMik90#180, AndyMik90#167

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
* feat: Add OpenRouter as LLM/embedding provider

Add OpenRouter provider support for Graphiti memory integration,
enabling access to multiple LLM providers through a single API.

Changes:
Backend:
- Created openrouter_llm.py: OpenRouter LLM provider using OpenAI-compatible API
- Created openrouter_embedder.py: OpenRouter embedder provider
- Updated config.py: Added OpenRouter to provider enums and configuration
  - New fields: openrouter_api_key, openrouter_base_url, openrouter_llm_model, openrouter_embedding_model
  - Validation methods updated for OpenRouter
- Updated factory.py: Added OpenRouter to LLM and embedder factories
- Updated provider __init__.py files: Exported new OpenRouter functions

Frontend:
- Updated project.ts types: Added 'openrouter' to provider type unions
  - GraphitiProviderConfig extended with OpenRouter fields
- Updated GraphitiStep.tsx: Added OpenRouter to provider arrays
  - LLM_PROVIDERS: 'Multi-provider aggregator'
  - EMBEDDING_PROVIDERS: 'OpenAI-compatible embeddings'
  - Added OpenRouter API key input field with show/hide toggle
  - Link to https://openrouter.ai/keys
- Updated env-handlers.ts: OpenRouter .env generation and parsing
  - Template generation for OPENROUTER_* variables
  - Parsing from .env files with proper type casting

Documentation:
- Updated .env.example with OpenRouter section
  - Configuration examples
  - Popular model recommendations
  - Example configuration (AndyMik90#6)

Fixes AndyMik90#92

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* refactor: address CodeRabbit review comments for OpenRouter

- Add globalOpenRouterApiKey to settings types and store updates
- Initialize openrouterApiKey from global settings
- Update documentation to include OpenRouter in provider lists
- Add OpenRouter handling to get_embedding_dimension() method
- Add openrouter to provider cleanup list
- Add OpenRouter to get_available_providers() function
- Clarify Legacy comment for openrouterLlmModel

These changes complete the OpenRouter integration by ensuring proper
settings persistence and provider detection across the application.

* fix: apply ruff formatting to OpenRouter code

- Break long error message across multiple lines
- Format provider list with one item per line
- Fixes lint CI failure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

---------

Co-authored-by: Claude Sonnet 4.5 <[email protected]>
…Mik90#209)

Implements distributed file-based locking for spec number coordination
across main project and all worktrees. Previously, parallel spec creation
could assign the same number to different specs (e.g., 042-bmad-task and
042-gitlab-integration both using number 042).

The fix adds SpecNumberLock class that:
- Acquires exclusive lock before calculating spec numbers
- Scans ALL locations (main project + worktrees) for global maximum
- Creates spec directories atomically within the lock
- Handles stale locks via PID-based detection with 30s timeout

Applied to both Python backend (spec_runner.py flow) and TypeScript
frontend (ideation conversion, GitHub/GitLab issue import).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 4.5 <[email protected]>
* fix(ideation): add missing event forwarders for status sync

- Add event forwarders in ideation-handlers.ts for progress, log,
  type-complete, type-failed, complete, error, and stopped events
- Fix ideation-type-complete to load actual ideas array from JSON files
  instead of emitting only the count

Resolves UI getting stuck at 0/3 complete during ideation generation.

* fix(ideation): fix UI not updating after actions

- Fix getIdeationSummary to count only active ideas (exclude dismissed/archived)
  This ensures header stats match the visible ideas count
- Add transformSessionFromSnakeCase to properly transform session data
  from backend snake_case to frontend camelCase on ideation-complete event
- Transform raw session before emitting ideation-complete event

Resolves header showing stale counts after dismissing/deleting ideas.

* fix(ideation): improve type safety and async handling in ideation type completion

- Replace synchronous readFileSync with async fsPromises.readFile in ideation-type-complete handler
- Wrap async file read in IIFE with proper error handling to prevent unhandled promise rejections
- Add type validation for IdeationType with VALID_IDEATION_TYPES set and isValidIdeationType guard
- Add validateEnabledTypes function to filter out invalid type values and log dropped entries
- Handle ENOENT separately

* fix(ideation): improve generation state management and error handling

- Add explicit isGenerating flag to prevent race conditions during async operations
- Implement 5-minute timeout for generation with automatic cleanup and error state
- Add ideation-stopped event emission when process is intentionally killed
- Replace console.warn/error with proper ideation-error events in agent-queue
- Add resetGeneratingTypes helper to transition all generating types to a target state
- Filter out dismissed/

* refactor(ideation): improve event listener cleanup and timeout management

- Extract event handler functions in ideation-handlers.ts to enable proper cleanup
- Return cleanup function from registerIdeationHandlers to remove all listeners
- Replace single generationTimeoutId with Map to support multiple concurrent projects
- Add clearGenerationTimeout helper to centralize timeout cleanup logic
- Extract loadIdeationType IIFE to named function for better error context
- Enhance error logging with projectId,

* refactor: use async file read for ideation and roadmap session loading

- Replace synchronous readFileSync with async fsPromises.readFile
- Prevents blocking the event loop during file operations
- Consistent with async pattern used elsewhere in the codebase
- Improved error handling with proper event emission

* fix(agent-queue): improve roadmap completion handling and error reporting

- Add transformRoadmapFromSnakeCase to convert backend snake_case to frontend camelCase
- Transform raw roadmap data before emitting roadmap-complete event
- Add roadmap-error emission for unexpected errors during completion
- Add roadmap-error emission when project path is unavailable
- Remove duplicate ideation-type-complete emission from error handler (event already emitted in loadIdeationType)
- Update error log message
Adds 'from __future__ import annotations' to spec/discovery.py for
Python 3.9+ compatibility with type hints.

This completes the Python compatibility fixes that were partially
applied in previous commits. All 26 analysis and spec Python files
now have the future annotations import.

Related: AndyMik90#128

Co-authored-by: Joris Slagter <[email protected]>
…#241)

* fix: resolve Python detection and backend packaging issues

- Fix backend packaging path (auto-claude -> backend) to match path-resolver.ts expectations
- Add future annotations import to config_parser.py for Python 3.9+ compatibility
- Use findPythonCommand() in project-context-handlers to prioritize Homebrew Python
- Improve Python detection to prefer Homebrew paths over system Python on macOS

This resolves the following issues:
- 'analyzer.py not found' error due to incorrect packaging destination
- TypeError with 'dict | None' syntax on Python < 3.10
- Wrong Python interpreter being used (system Python instead of Homebrew Python 3.10+)

Tested on macOS with packaged app - project index now loads successfully.

* refactor: address PR review feedback

- Extract findHomebrewPython() helper to eliminate code duplication between
  findPythonCommand() and getDefaultPythonCommand()
- Remove hardcoded version-specific paths (python3.12) and rely only on
  generic Homebrew symlinks for better maintainability
- Remove unnecessary 'from __future__ import annotations' from config_parser.py
  since backend requires Python 3.12+ where union types are native

These changes make the code more maintainable, less fragile to Python version
changes, and properly reflect the project's Python 3.12+ requirement.
…#250)

* feat(github): add GitHub automation system for issues and PRs

Implements comprehensive GitHub automation with three major components:

1. Issue Auto-Fix: Automatically creates specs from labeled issues
   - AutoFixButton component with progress tracking
   - useAutoFix hook for config and queue management
   - Backend handlers for spec creation from issues

2. GitHub PRs Tool: AI-powered PR review sidebar
   - New sidebar tab (Cmd+Shift+P) alongside GitHub Issues
   - PRList/PRDetail components for viewing PRs
   - Review system with findings by severity
   - Post review comments to GitHub

3. Issue Triage: Duplicate/spam/feature-creep detection
   - Triage handlers with label application
   - Configurable detection thresholds

Also adds:
- Debug logging (DEBUG=true) for all GitHub handlers
- Backend runners/github module with orchestrator
- AI prompts for PR review, triage, duplicate/spam detection
- dev:debug npm script for development with logging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(github-runner): resolve import errors for direct script execution

Changes runner.py and orchestrator.py to handle both:
- Package import: `from runners.github import ...`
- Direct script: `python runners/github/runner.py`

Uses try/except pattern for relative vs direct imports.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(github): correct argparse argument order for runner.py

Move --project global argument before subcommand so argparse can
correctly parse it. Fixes "unrecognized arguments: --project" error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* logs when debug mode is on

* refactor(github): extract service layer and fix linting errors

Major refactoring to improve maintainability and code quality:

Backend (Python):
- Extracted orchestrator.py (2,600 → 835 lines, 68% reduction) into 7 service modules:
  - prompt_manager.py: Prompt template management
  - response_parsers.py: AI response parsing
  - pr_review_engine.py: PR review orchestration
  - triage_engine.py: Issue triage logic
  - autofix_processor.py: Auto-fix workflow
  - batch_processor.py: Batch issue handling
- Fixed 18 ruff linting errors (F401, C405, C414, E741):
  - Removed unused imports (BatchValidationResult, AuditAction, locked_json_write)
  - Optimized collection literals (set([n]) → {n})
  - Removed unnecessary list() calls
  - Renamed ambiguous variable 'l' to 'label' throughout

Frontend (TypeScript):
- Refactored IPC handlers (19% overall reduction) with shared utilities:
  - autofix-handlers.ts: 1,042 → 818 lines
  - pr-handlers.ts: 648 → 543 lines
  - triage-handlers.ts: 437 lines (no duplication)
- Created utils layer: logger, ipc-communicator, project-middleware, subprocess-runner
- Split github-store.ts into focused stores: issues, pr-review, investigation, sync-status
- Split ReviewFindings.tsx into focused components

All imports verified, type checks passing, linting clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
* Add multilingual support and i18n integration

- Implemented i18n framework using `react-i18next` for translation management.
- Added support for English and French languages with translation files.
- Integrated language selector into settings.
- Updated all text strings in UI components to use translation keys.
- Ensured smooth language switching with live updates.

* Migrate remaining hard-coded strings to i18n system

- TaskCard: status labels, review reasons, badges, action buttons
- PhaseProgressIndicator: execution phases, progress labels
- KanbanBoard: drop zone, show archived, tooltips
- CustomModelModal: dialog title, description, labels
- ProactiveSwapListener: account switch notifications
- AgentProfileSelector: phase labels, custom configuration
- GeneralSettings: agent framework option

Added translation keys for en/fr locales in tasks.json, common.json,
and settings.json for complete i18n coverage.

* Add i18n support to dialogs and settings components

- AddFeatureDialog: form labels, validation messages, buttons
- AddProjectModal: dialog steps, form fields, actions
- RateLimitIndicator: rate limit notifications
- RateLimitModal: account switching, upgrade prompts
- AdvancedSettings: updates and notifications sections
- ThemeSettings: theme selection labels
- Updated dialogs.json locales (en/fr)

* Fix truncated 'ready' message in dialogs locales

* Fix backlog terminology in i18n locales

Change "Planning"/"Planification" to standard PM term "Backlog"

* Migrate settings navigation and integration labels to i18n

- AppSettings: nav items, section titles, buttons
- IntegrationSettings: Claude accounts, auto-switch, API keys labels
- Added settings nav/projectSections/integrations translation keys
- Added buttons.saving to common translations

* Migrate AgentProfileSettings and Sidebar init dialog to i18n

- AgentProfileSettings: migrate phase config labels, section title,
  description, and all hardcoded strings to settings namespace
- Sidebar: migrate init dialog strings to dialogs namespace with
  common buttons from common namespace
- Add new translation keys for agent profile settings and update dialog

* Migrate AppSettings navigation labels to i18n

- Add useTranslation hook to AppSettings.tsx
- Replace hardcoded section labels with dynamic translations
- Add projectSections translations for project settings nav
- Add rerunWizardDescription translation key

* Add explicit typing to notificationItems array

Import NotificationSettings type and use keyof to properly type
the notification item keys, removing manual type assertion.
…AndyMik90#266)

* ci: implement enterprise-grade PR quality gates and security scanning

* ci: implement enterprise-grade PR quality gates and security scanning

* fix:pr comments and improve code

* fix: improve commit linting and code quality

* Removed the dependency-review job (i added it)

* fix: address CodeRabbit review comments

- Expand scope pattern to allow uppercase, underscores, slashes, dots
- Add concurrency control to cancel duplicate security scan runs
- Add explanatory comment for Bandit CLI flags
- Remove dependency-review job (requires repo settings)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* docs: update commit lint examples with expanded scope patterns

Show slashes and dots in scope examples to demonstrate
the newly allowed characters (api/users, package.json)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* chore: remove feature request issue template

Feature requests are directed to GitHub Discussions
via the issue template config.yml

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix: address security vulnerabilities in service orchestrator

- Fix port parsing crash on malformed docker-compose entries
- Fix shell injection risk by using shlex.split() with shell=False

Prevents crashes when docker-compose.yml contains environment
variables in port mappings (e.g., '${PORT}:8080') and eliminates
shell injection vulnerabilities in subprocess execution.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
…90#252)

* feat(github): add GitHub automation system for issues and PRs

Implements comprehensive GitHub automation with three major components:

1. Issue Auto-Fix: Automatically creates specs from labeled issues
   - AutoFixButton component with progress tracking
   - useAutoFix hook for config and queue management
   - Backend handlers for spec creation from issues

2. GitHub PRs Tool: AI-powered PR review sidebar
   - New sidebar tab (Cmd+Shift+P) alongside GitHub Issues
   - PRList/PRDetail components for viewing PRs
   - Review system with findings by severity
   - Post review comments to GitHub

3. Issue Triage: Duplicate/spam/feature-creep detection
   - Triage handlers with label application
   - Configurable detection thresholds

Also adds:
- Debug logging (DEBUG=true) for all GitHub handlers
- Backend runners/github module with orchestrator
- AI prompts for PR review, triage, duplicate/spam detection
- dev:debug npm script for development with logging

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(github-runner): resolve import errors for direct script execution

Changes runner.py and orchestrator.py to handle both:
- Package import: `from runners.github import ...`
- Direct script: `python runners/github/runner.py`

Uses try/except pattern for relative vs direct imports.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(github): correct argparse argument order for runner.py

Move --project global argument before subcommand so argparse can
correctly parse it. Fixes "unrecognized arguments: --project" error.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* logs when debug mode is on

* refactor(github): extract service layer and fix linting errors

Major refactoring to improve maintainability and code quality:

Backend (Python):
- Extracted orchestrator.py (2,600 → 835 lines, 68% reduction) into 7 service modules:
  - prompt_manager.py: Prompt template management
  - response_parsers.py: AI response parsing
  - pr_review_engine.py: PR review orchestration
  - triage_engine.py: Issue triage logic
  - autofix_processor.py: Auto-fix workflow
  - batch_processor.py: Batch issue handling
- Fixed 18 ruff linting errors (F401, C405, C414, E741):
  - Removed unused imports (BatchValidationResult, AuditAction, locked_json_write)
  - Optimized collection literals (set([n]) → {n})
  - Removed unnecessary list() calls
  - Renamed ambiguous variable 'l' to 'label' throughout

Frontend (TypeScript):
- Refactored IPC handlers (19% overall reduction) with shared utilities:
  - autofix-handlers.ts: 1,042 → 818 lines
  - pr-handlers.ts: 648 → 543 lines
  - triage-handlers.ts: 437 lines (no duplication)
- Created utils layer: logger, ipc-communicator, project-middleware, subprocess-runner
- Split github-store.ts into focused stores: issues, pr-review, investigation, sync-status
- Split ReviewFindings.tsx into focused components

All imports verified, type checks passing, linting clean.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fixes during testing of PR

* feat(github): implement PR merge, assign, and comment features

- Add auto-assignment when clicking "Run AI Review"
- Implement PR merge functionality with squash method
- Add ability to post comments on PRs
- Display assignees in PR UI
- Add Approve and Merge buttons when review passes
- Update backend gh_client with pr_merge, pr_comment, pr_assign methods
- Create IPC handlers for new PR operations
- Update TypeScript interfaces and browser mocks

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* Improve PR review AI

* fix(github): use temp files for PR review posting to avoid shell escaping issues

When posting PR reviews with findings containing special characters (backticks,
parentheses, quotes), the shell command was interpreting them as commands instead
of literal text, causing syntax errors.

Changed both postPRReview and postPRComment handlers to write the body content
to temporary files and use gh CLI's --body-file flag instead of --body with
inline content. This safely handles ALL special characters without escaping issues.

Fixes shell errors when posting reviews with suggested fixes containing code snippets.

* fix(i18n): add missing GitHub PRs translation and document i18n requirements

Fixed missing translation key for GitHub PRs feature that was causing
"items.githubPRs" to display instead of the proper translated text.

Added comprehensive i18n guidelines to CLAUDE.md to ensure all future
frontend development follows the translation key pattern instead of
using hardcoded strings.

Also fixed missing deletePRReview mock function in browser-mock.ts
to resolve TypeScript compilation errors.

Changes:
- Added githubPRs translation to en/navigation.json
- Added githubPRs translation to fr/navigation.json
- Added Development Guidelines section to CLAUDE.md with i18n requirements
- Documented translation file locations and namespace usage patterns
- Added deletePRReview mock function to browser-mock.ts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* fix ui loading

* Github PR fixes

* improve claude.md

* lints/tests

* fix(github): handle PRs exceeding GitHub's 20K line diff limit

- Add PRTooLargeError exception for large PR detection
- Update pr_diff() to catch and raise PRTooLargeError for HTTP 406 errors
- Gracefully handle large PRs by skipping full diff and using individual file patches
- Add diff_truncated flag to PRContext to track when diff was skipped
- Large PRs will now review successfully using per-file diffs instead of failing

Fixes issue with PR AndyMik90#252 which has 100+ files exceeding the 20,000 line limit.

* fix: implement individual file patch fetching for large PRs

The PR review was getting stuck for large PRs (>20K lines) because when we
skipped the full diff due to GitHub API limits, we had no code to analyze.
The individual file patches were also empty, leaving the AI with just
file names and metadata.

Changes:
- Implemented _get_file_patch() to fetch individual patches via git diff
- Updated PR review engine to build composite diff from file patches when
  diff_truncated is True
- Added missing 'state' field to PRContext dataclass
- Limits composite diff to first 50 files for very large PRs
- Shows appropriate warnings when using reconstructed diffs

This allows AI review to proceed with actual code analysis even when the
full PR diff exceeds GitHub's limits.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>

* 1min reduction

* docs: add GitHub Sponsors funding configuration

Enable the Sponsor button on the repository by adding FUNDING.yml
with the AndyMik90 GitHub Sponsors profile.

* feat(github-pr): add orchestrating agent for thorough PR reviews

Implement a new Opus 4.5 orchestrating agent that performs comprehensive
PR reviews regardless of size. Key changes:

- Add orchestrator_reviewer.py with strategic review workflow
- Add review_tools.py with subagent spawning capabilities
- Add pr_orchestrator.md prompt emphasizing thorough analysis
- Add pr_security_agent.md and pr_quality_agent.md subagent prompts
- Integrate orchestrator into pr_review_engine.py with config flag
- Fix critical bug where findings were extracted but not processed
  (indentation issue in _parse_orchestrator_output)

The orchestrator now correctly identifies issues in PRs that were
previously approved as "trivial". Testing showed 7 findings detected
vs 0 before the fix.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* i18n

* fix(github-pr): restrict pr_reviewer to read-only permissions

The PR review agent was using qa_reviewer agent type which has Bash
access, allowing it to checkout branches and make changes during
review. Created new pr_reviewer agent type with BASE_READ_TOOLS only
(no Bash, no writes, no auto-claude tools).

This prevents the PR review from accidentally modifying code or
switching branches during analysis.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(github-pr): robust category mapping and JSON parsing for PR review

The orchestrator PR review was failing to extract findings because:

1. AI generates category names like 'correctness', 'consistency', 'testing'
   that aren't in our ReviewCategory enum - added flexible mapping

2. JSON sometimes embedded in markdown code blocks (```json) which broke
   parsing - added code block extraction as first parsing attempt

Changes:
- Add _CATEGORY_MAPPING dict to map AI categories to valid enum values
- Add _map_category() helper function with fallback to QUALITY
- Add severity parsing with fallback to MEDIUM
- Add markdown code block detection (```json) before raw JSON parsing
- Add _extract_findings_from_data() helper to reduce code duplication
- Apply same fixes to review_tools.py for subagent parsing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(pr-review): improve post findings UX with batch support and feedback

- Fix post findings failing on own PRs by falling back from REQUEST_CHANGES
  to COMMENT when GitHub returns 422 error
- Change status badge to show "Reviewed" instead of "Commented" until
  findings are actually posted to GitHub
- Add success notification when findings are posted (auto-dismisses after 3s)
- Add batch posting support: track posted findings, show "Posted" badge,
  allow posting remaining findings in additional batches
- Show loading state on button while posting

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(github): resolve stale timestamp and null author bugs

- Fix stale timestamp in batch_issues.py: Move updated_at assignment
  BEFORE to_dict() serialization so the saved JSON contains the correct
  timestamp instead of the old value

- Fix AttributeError in context_gatherer.py: Handle null author/user
  fields when GitHub API returns null for deleted/suspended users
  instead of an empty object

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(security): address all high and medium severity PR review findings

HIGH severity fixes:
- Command Injection in autofix-handlers.ts: Use execFileSync with args array
- Command Injection in pr-handlers.ts (3 locations): Use execFileSync + validation
- Command Injection in triage-handlers.ts: Use execFileSync + label validation
- Token Exposure in bot_detection.py: Pass token via GH_TOKEN env var

MEDIUM severity fixes:
- Environment variable leakage in subprocess-runner.ts: Filter to safe vars only
- Debug logging in subprocess-runner.ts: Only log in development mode
- Delimiter escape bypass in sanitize.py: Use regex pattern for variations
- Insecure file permissions in trust.py: Use os.open with 0o600 mode
- No file locking in learning.py: Use FileLock + atomic_write utilities
- Bare except in confidence.py: Log error with specific exception info
- Fragile module import in pr_review_engine.py: Import at module level
- State transition validation in models.py: Enforce can_transition_to()

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* PR followup

* fix(security): add usedforsecurity=False to MD5 hash calls

MD5 is used for generating unique IDs/cache keys, not for security purposes.
Adding usedforsecurity=False resolves Bandit B324 warnings.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(security): address all high-priority PR review findings

Fixes 5 high-priority issues from Auto Claude PR Review:

1. orchestrator_reviewer.py: Token budget tracking now increments
   total_tokens from API response usage data

2. pr_review_engine.py: Async exceptions now re-raise RuntimeError
   instead of silently returning empty results

3. batch_issues.py: IssueBatch.save() now uses locked_json_write
   for atomic file operations with file locking

4. project-middleware.ts: Added validateProjectPath() to prevent
   path traversal attacks (checks absolute, no .., exists, is dir)

5. orchestrator.py: Exception handling now logs full traceback and
   preserves exception type/context in error messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* fix(security): address all high-priority PR review findings

Fixes 5 high-priority issues from Auto Claude PR Review:

1. orchestrator_reviewer.py: Token budget tracking now increments
   total_tokens from API response usage data

2. pr_review_engine.py: Async exceptions now re-raise RuntimeError
   instead of silently returning empty results

3. batch_issues.py: IssueBatch.save() now uses locked_json_write
   for atomic file operations with file locking

4. project-middleware.ts: Added validateProjectPath() to prevent
   path traversal attacks (checks absolute, no .., exists, is dir)

5. orchestrator.py: Exception handling now logs full traceback and
   preserves exception type/context in error messages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* feat(ui): add PR status labels to list view

Add secondary status badges to the PR list showing review state at a glance:
- "Changes Requested" (warning) - PRs with blocking issues (critical/high)
- "Ready to Merge" (green) - PRs with only non-blocking suggestions
- "Ready for Follow-up" (blue) - PRs with new commits since last review

The "Ready for Follow-up" badge uses a cached new commits check from the
store, only shown after the detail view confirms new commits via SHA
comparison. This prevents false positives from PR updatedAt timestamp
changes (which can happen from comments, labels, etc).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

* PR labels

* auto-claude: Initialize subtask-based implementation plan

- Workflow type: feature
- Phases: 3
- Subtasks: 6
- Ready for autonomous implementation

---------

Co-authored-by: Claude Opus 4.5 <[email protected]>
…yMik90#272)

Bumps [vitest](https://github.com/vitest-dev/vitest/tree/HEAD/packages/vitest) from 4.0.15 to 4.0.16.
- [Release notes](https://github.com/vitest-dev/vitest/releases)
- [Commits](https://github.com/vitest-dev/vitest/commits/v4.0.16/packages/vitest)

---
updated-dependencies:
- dependency-name: vitest
  dependency-version: 4.0.16
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Bumps [@electron/rebuild](https://github.com/electron/rebuild) from 3.7.2 to 4.0.2.
- [Release notes](https://github.com/electron/rebuild/releases)
- [Commits](electron/rebuild@v3.7.2...v4.0.2)

---
updated-dependencies:
- dependency-name: "@electron/rebuild"
  dependency-version: 4.0.2
  dependency-type: direct:development
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Andy <[email protected]>
* fix(planning): accept bug_fix workflow_type alias

* style(planning): ruff format

* fix: refatored common logic

* fix: remove ruff errors

* fix: remove duplicate _normalize_workflow_type method

Remove the incorrectly placed duplicate method inside ContextLoader class.
The module-level function is the correct implementation being used.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

---------

Co-authored-by: danielfrey63 <[email protected]>
Co-authored-by: Andy <[email protected]>
Co-authored-by: AndyMik90 <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
…ow (AndyMik90#276)

When dry_run=true, the workflow skipped creating the version tag but
build jobs still tried to checkout that non-existent tag, causing all
4 platform builds to fail with "git failed with exit code 1".

Now build jobs checkout develop branch for dry runs while still using
the version tag for real releases.

Closes: GitHub Actions run #20464082726
@xytras1
Copy link

xytras1 commented Jan 11, 2026

Workaround confirmed on Windows:

Adding Claude CLI path (C:\Users\<user>\.local\bin) to System PATH did not resolve the "Claude CLI not found" error.

However, launching Auto-Claude from a terminal where claude --version works does work:

# Git Bash / MINGW
"/c/Users/<user>/AppData/Local/Programs/auto-claude-ui/Auto-Claude.exe"

# Or CMD/PowerShell
"C:\Users\<user>\AppData\Local\Programs\auto-claude-ui\Auto-Claude.exe"

This suggests the Electron app isn't inheriting the system PATH properly on startup, but does inherit the terminal's environment when launched from command line.

…ling (AndyMik90#839)

* fix(ACS-175): Resolve integrations freeze and improve rate limit handling

* fix(i18n): replace hardcoded toast strings with translation keys

Addresses CodeRabbit review feedback on PR AndyMik90#839:
- OAuthStep.tsx: use t() for all toast messages
- RateLimitModal.tsx: use t() for toast messages
- SDKRateLimitModal.tsx: add useTranslation hook, use t() for toasts
- Add toast translation keys to en/fr onboarding.json and common.json

* fix: replace console.log with debugLog in IntegrationSettings

Addresses CodeRabbit review feedback - use project's debug logging
utility for consistent and toggle-able logging in production.

* fix: replace console.log with debugLog in main process files

Addresses Auto-Claude PR Review feedback:
- terminal-handlers.ts: 14 console.log → debugLog
- pty-manager.ts: 10 console.log → debugLog/debugError
- terminal-manager.ts: 4 console.log → debugLog/debugError

Also fixes:
- Extract magic numbers to CHUNKED_WRITE_THRESHOLD/CHUNK_SIZE constants
- Add terminal validity check before chunked writes
- Consistent error handling (no rethrow for fire-and-forget semantics)

* fix: address Auto Claude PR review findings - console.error→debugError + i18n

- Replace 8 remaining console.error/warn calls with debugError/debugLog:
  - terminal-handlers.ts: lines 59, 426, 660, 671
  - terminal-manager.ts: lines 88, 320
  - pty-manager.ts: lines 88, 141
  - Fixed duplicate logging in exception handler

- Add comprehensive i18n for SDKRateLimitModal.tsx (~20 strings):
  - Added rateLimit.sdk.* keys with swap notifications, buttons, labels
  - EN + FR translations in common.json

- Add comprehensive i18n for OAuthStep.tsx (~15 strings):
  - Added oauth.badges.*, oauth.buttons.*, oauth.labels.* keys
  - EN + FR translations in onboarding.json

All MEDIUM severity findings resolved except race condition (deferred).

* fix: address Auto Claude PR review findings - race condition + console.error

- Fix race condition in chunked PTY writes by serializing writes per terminal
  using Promise chaining (prevents interleaving of concurrent large writes)
- Fix missing 't' in useEffect dependency array in OAuthStep.tsx
- Convert all remaining console.error calls to debugError for consistency:
  - IntegrationSettings.tsx (9 occurrences)
  - RateLimitModal.tsx (3 occurrences)
  - SDKRateLimitModal.tsx (4 occurrences)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Signed-off-by: Black Circle Sentinel <[email protected]>

---------

Signed-off-by: Black Circle Sentinel <[email protected]>
Co-authored-by: Andy <[email protected]>
Co-authored-by: Adam Slaker <[email protected]>
Co-authored-by: Claude Opus 4.5 <[email protected]>
VDT-91 pushed a commit to VDT-91/Auto-Claude that referenced this pull request Jan 12, 2026
… detection

Problem:
Windows Electron GUI apps don't inherit the full PATH from the user's
shell environment. When users add Claude CLI to their Windows PATH via
System Settings, the app still couldn't find it because process.env.PATH
was incomplete/stale.

Solution:
Read the TRUE Windows PATH directly from the Windows Registry:
- HKCU\Environment\Path (User PATH)
- HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment\Path (System PATH)

This bypasses the PATH inheritance issue entirely.

New Detection Order (Windows):
1. Registry PATH (HKCU + HKLM) - TRUE Windows PATH
2. Known installation paths (~\.local\bin, npm, Scoop, Chocolatey)
3. nvm-windows paths (%APPDATA%\nvm\vX.X.X\...)
4. Augmented process.env.PATH (fallback)
5. where.exe (last resort)
6. User config from settings.json (manual override)

macOS/Linux detection order unchanged.

New Functions:
- parseRegOutput() - Parse reg.exe query output
- expandWindowsEnvVars() - Expand %USERPROFILE%, %APPDATA%, etc.
- getWindowsRegistryPath() - Read PATH from Registry
- findClaudeInRegistryPath() - Search for Claude in Registry PATH
- getNvmWindowsPaths() - Support nvm-windows installations

Tests:
Added 37 new tests covering:
- Registry PATH parsing and expansion
- nvm-windows detection
- Windows detection order verification
- Cross-platform safety (macOS/Linux unchanged)

All 61 tests pass.

Edge Cases Handled:
- Environment variables in Registry paths (%USERPROFILE%\.local\bin)
- reg.exe blocked by Group Policy (falls back to known paths)
- Custom NVM_HOME for nvm-windows users
- Multiple Claude install methods (official, npm, Scoop, Chocolatey)

Closes feedback from xytras1 on PR AndyMik90#837.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@VDT-91
Copy link
Author

VDT-91 commented Jan 12, 2026

Follow-up Fix: Windows Registry PATH Detection

Thanks for the feedback @xytras1! Your report helped identify the root cause.

The Problem

Windows Electron GUI apps don't inherit the full PATH from the user's shell environment. When you add Claude CLI to your Windows PATH via System Settings, process.env.PATH in the Electron app may not reflect this change until the system is restarted or Explorer.exe is restarted.

This is why launching from terminal worked (terminal has correct PATH) but launching from Start Menu/Desktop didn't.

The Fix

We now read the TRUE Windows PATH directly from the Windows Registry:

  • HKEY_CURRENT_USER\Environment\Path (User PATH)
  • HKEY_LOCAL_MACHINE\SYSTEM\...\Environment\Path (System PATH)

This bypasses the PATH inheritance issue entirely.

New Windows Detection Order

1. Registry PATH (HKCU + HKLM)     ← NEW: TRUE Windows PATH
2. Known paths (~\.local\bin, npm, Scoop, Chocolatey)
3. nvm-windows paths               ← NEW: Support for nvm-windows
4. Augmented process.env.PATH      (fallback)
5. where.exe                       (last resort)
6. User config                     (manual override)

macOS/Linux detection unchanged.

Testing

  • Added 37 new tests (61 total, all passing)
  • Covers Registry parsing, env var expansion, nvm-windows, detection order
  • Cross-platform safety verified (macOS/Linux tests still pass)

Edge Cases Handled

  • ✅ Environment variables in Registry (%USERPROFILE%\.local\bin)
  • reg.exe blocked by Group Policy (falls back to known paths)
  • ✅ Custom NVM_HOME for nvm-windows users
  • ✅ Multiple install methods (official installer, npm, Scoop, Chocolatey)

@xytras1 - Can you test this fix when it's merged? The Claude CLI should now be detected even when launched from Start Menu/Desktop.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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

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/__tests__/cli-tool-manager.test.ts (1)

273-286: Bug: pathStr is referenced but not defined in the callback scope.

The existsSync mock implementation references pathStr which is not defined within that function. This will cause a ReferenceError at runtime.

🐛 Proposed fix
     it('should handle NVM directory with no version subdirectories', () => {
       vi.mocked(os.homedir).mockReturnValue(mockHomeDir);

       vi.mocked(existsSync).mockImplementation((filePath) => {
-        return String(filePath).includes('.nvm') && pathStr.includes('versions') && pathStr.includes('node');
+        const pathStr = String(filePath);
+        return pathStr.includes('.nvm') && pathStr.includes('versions') && pathStr.includes('node');
       });

       // Empty NVM directory
       vi.mocked(readdirSync).mockReturnValue([]);

       const result = getToolInfo('claude');

       expect(result.source).not.toBe('nvm');
     });
🤖 Fix all issues with AI agents
In @apps/frontend/src/main/cli-tool-manager.ts:
- Around line 352-407: The current getWindowsRegistryPath uses blocking
execFileSync which can stall the main thread; add an async counterpart
getWindowsRegistryPathAsync that mirrors getWindowsRegistryPath but uses an
async execFile (e.g., child_process.promises.execFile or promisified execFile)
with the same args, timeouts and reuses parseRegOutput for parsing, returning
Promise<string | null>; then update detectClaudeAsync to call
getWindowsRegistryPathAsync instead of the sync findClaudeInRegistryPath/path
usage (and refactor or remove findClaudeInRegistryPath if redundant) so all
registry reads in async flows are non-blocking.
- Around line 1534-1612: The async Windows detection path calls the synchronous
registry helper findClaudeInRegistryPath(), which uses execFileSync and blocks
the event loop; create an async variant (e.g., findClaudeInRegistryPathAsync)
that uses child_process.execFile (or promisified execFile) and returns a
Promise<string|undefined>, import/use that in detectClaudeAsync (replace the
call at the top of the Windows branch with await
findClaudeInRegistryPathAsync()), and ensure any related helpers/exports and
callers are updated (and remove or keep the sync version only for sync detection
code) so validateClaudeAsync is awaited against the async registry result.
- Line 428: The extensions array includes an empty string which contradicts the
JSDoc and can match names without extensions; remove the '' entry from the const
extensions = ['.exe', '.cmd', '.bat'] and update the surrounding JSDoc to state
explicitly that the function only checks .exe, .cmd, and .bat extensions (adjust
any callers expecting a bare filename if necessary).
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a45e07 and aee3a63.

📒 Files selected for processing (2)
  • apps/frontend/src/main/__tests__/cli-tool-manager.test.ts
  • apps/frontend/src/main/cli-tool-manager.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/__tests__/cli-tool-manager.test.ts
  • apps/frontend/src/main/cli-tool-manager.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/__tests__/cli-tool-manager.test.ts
  • apps/frontend/src/main/cli-tool-manager.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/__tests__/cli-tool-manager.test.ts
  • apps/frontend/src/main/cli-tool-manager.ts
🧠 Learnings (1)
📓 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.
🧬 Code graph analysis (1)
apps/frontend/src/main/__tests__/cli-tool-manager.test.ts (1)
apps/frontend/src/main/cli-tool-manager.ts (8)
  • getClaudeDetectionPaths (164-202)
  • parseRegOutput (297-310)
  • expandWindowsEnvVars (326-337)
  • getWindowsRegistryPath (352-407)
  • findClaudeInRegistryPath (417-443)
  • getNvmWindowsPaths (462-498)
  • getToolInfo (2147-2165)
  • getToolInfo (2239-2241)
🔇 Additional comments (17)
apps/frontend/src/main/cli-tool-manager.ts (8)

172-193: Good expansion of Windows platform paths.

The addition of multiple installation locations (npm global, Scoop, Local Programs, Chocolatey) significantly improves Claude CLI discovery on Windows. The inclusion of both .exe and .cmd extensions is correct for covering different installation methods.


297-310: LGTM - Registry output parsing looks correct.

The regex handles both REG_SZ and REG_EXPAND_SZ types and properly trims whitespace. The early return for empty or error output is appropriate.


326-337: LGTM - Environment variable expansion is correctly implemented.

The early return when no % is present avoids unnecessary processing. Returning the original placeholder for undefined variables is safe behavior.


462-498: LGTM - nvm-windows detection is well implemented.

Good handling of:

  • NVM_HOME environment variable override
  • Proper version directory filtering with regex
  • Descending version sort (newest first)
  • Graceful error handling for directory read failures

935-1047: Detection order prioritizes automatic discovery over user config on Windows.

The new Windows detection order places user config at position 6 (lowest priority), which differs from other tools like Python/Git where user config is priority 1. This is intentional based on PR objectives (fixing the race condition), but the behavior difference between tools may be surprising.

However, looking at getToolInfo() (lines 2147-2165), user config IS checked first there before calling detectToolPath(). So the effective priority is correct - this order only applies when user config is not set or invalid.


2079-2114: Effective race condition fix by reading settings from disk.

The fallback to readSettingsFile() when in-memory config is empty correctly handles the case where getToolInfo() is called before configureTools() completes. This addresses the core issue described in the PR objectives.

One consideration: this introduces disk I/O on every getToolInfo() call when in-memory config is empty. For the race condition scenario, this only happens once at startup before settings load.


2147-2165: LGTM - Race condition fix is properly integrated.

The updated getToolInfo() now:

  1. Checks user-configured path first (from memory or disk)
  2. Validates the path before using it
  3. Falls back to detection only if user config is not set or invalid

This correctly addresses the Windows GUI launch race condition while maintaining expected behavior for user-configured paths.


30-30: The readSettingsFile import is correctly exported from settings-utils.

The import statement on line 30 properly references an exported function from ./settings-utils with the correct signature: export function readSettingsFile(): Record<string, unknown> | undefined. The function is used as expected in the new getUserConfiguredPath method.

apps/frontend/src/main/__tests__/cli-tool-manager.test.ts (9)

89-124: Good use of path-agnostic checks for cross-platform test execution.

Using .includes() checks for path segments instead of exact path matching ensures tests pass regardless of which OS runs them.


362-374: Good path-agnostic assertions for cross-platform compatibility.

The tests correctly verify path components rather than exact paths, allowing tests to pass on Windows where path.join uses backslashes even when the mocked platform is Linux.


501-552: Comprehensive tests for parseRegOutput function.

Good coverage including:

  • Standard REG_EXPAND_SZ output
  • REG_SZ type variant
  • Empty/error output handling
  • Paths with spaces

554-622: Good test coverage for expandWindowsEnvVars.

Tests cover the key environment variables (USERPROFILE, APPDATA, LOCALAPPDATA, SystemRoot) and edge cases (no variables, undefined variables).


624-723: Thorough tests for getWindowsRegistryPath.

Good coverage of:

  • Non-Windows platform guard
  • User and system PATH combination
  • Registry access failures
  • Missing user PATH scenario

725-834: Comprehensive tests for findClaudeInRegistryPath.

Tests verify:

  • Finding .exe and .cmd variants
  • Extension checking order
  • Negative case (not found)
  • Platform guard

861-1008: Good test coverage for nvm-windows paths.

Tests cover:

  • Default location detection
  • NVM_HOME override
  • npm global packages location
  • Version sorting
  • Error handling
  • Non-version directory filtering
  • Platform guard

1054-1219: Excellent tests for Windows detection order.

Tests verify:

  • Registry PATH is checked before process.env.PATH
  • Fallback to known paths when registry fails
  • Official installer location (.local/bin)
  • User config as last resort
  • macOS and Linux detection order is preserved

1225-1277: Good coverage of Windows known paths in getClaudeDetectionPaths.

Tests verify all expected installation locations are included and that both .exe and .cmd extensions are checked.

… messages (ACS-219) (AndyMik90#933)

* fix(frontend): strip ANSI escape codes from roadmap/ideation progress messages (ACS-219)

- Create ansi-sanitizer.ts utility with stripAnsiCodes() function
- Apply to roadmap and ideation progress handlers in agent-queue.ts
- Add 34 comprehensive test cases covering ANSI escape patterns
- Fixes raw escape codes (e.g., \x1b[90m) displaying in UI

* fix(frontend): extract first line before truncating roadmap progress messages

Make roadmap progress message construction consistent with ideation by
extracting the first line (split by newline) before applying the 200
character truncation. This ensures multi-line log output doesn't display
partial lines in the UI.

* refactor(frontend): extract repeated status message formatting to helper

Add formatStatusMessage() helper function to centralize the sanitize+truncate
pattern used in progress message handlers. This improves maintainability by:

- Adding STATUS_MESSAGE_MAX_LENGTH constant (200)
- Encapsulating ANSI stripping, line extraction, and truncation
- Replacing 4 duplicated call sites with single helper

Refactors lines 442, 461, 704, 718 to use formatStatusMessage(log).

---------

Co-authored-by: StillKnotKnown <[email protected]>
@VDT-91 VDT-91 force-pushed the fix/windows-claude-cli-detection-race branch from aee3a63 to e552099 Compare January 12, 2026 11:44
@VDT-91
Copy link
Author

VDT-91 commented Jan 12, 2026

Rebased onto latest develop

This PR has been rebased onto the latest develop branch to resolve merge conflicts. The previous commits were consolidated into a single focused commit.

Summary of Changes

The core fix addresses the Windows GUI app PATH inheritance issue reported by @xytras1:

Problem: Electron GUI apps don't inherit the shell's PATH environment variable. Even though claude --version works in terminal, the desktop app fails to find Claude CLI.

Solution: Read the TRUE Windows PATH directly from the Windows Registry:

  1. Registry PATH Reading

    • parseRegOutput() - Parse reg.exe query output
    • expandWindowsEnvVars() - Expand %USERPROFILE%, %APPDATA%, etc.
    • getWindowsRegistryPath() - Read from HKLM (System) + HKCU (User)
    • findClaudeInRegistryPath() - Search for Claude in Registry PATH
  2. nvm-windows Support

    • getNvmWindowsPaths() - Support for nvm-windows installations (%APPDATA%\nvm\vX.X.X\)
  3. Expanded Known Paths

    • Scoop: ~\scoop\shims\
    • Chocolatey: C:\ProgramData\chocolatey\bin\
    • npm global: %APPDATA%\npm\
    • Official installer: %LOCALAPPDATA%\Programs\claude\
  4. Updated Detection Order

    1. Windows Registry PATH (TRUE system PATH)
    2. User configuration (fallback)
    3. System PATH (augmented)
    4. where.exe lookup
    5. nvm-windows paths
    6. Known installation paths
    

The Registry PATH is now checked FIRST on Windows, which should resolve the issue where Claude is installed and working in terminal but not found by the Electron app.

/cc @xytras1 - Would appreciate if you could test this fix when it's merged!

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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/cli-tool-manager.ts:
- Around line 328-373: The getWindowsRegistryPath function currently pushes
System PATH before User PATH, reversing Windows' precedence; change the logic so
the User PATH is applied before the System PATH (either query HKCU first, or
push userPath before systemPath or use unshift for userPath) so that
expandWindowsEnvVars(parseRegOutput(...)) for the user registry entry ends up
earlier in the returned paths array; keep error handling and the final join(';')
intact.
- Around line 457-496: getNvmWindowsPaths duplicates the version
sorting/validation logic from sortNvmVersionDirs and only checks
startsWith('v'), allowing invalid dirs; remove the inline sort and validation
and instead call the existing sortNvmVersionDirs helper to produce versionDirs
(ensuring you pass the raw directory names or Dirent list as expected), keep the
initial existsSync/readdirSync and Dirent filtering for isDirectory, then feed
the filtered names into sortNvmVersionDirs so you get the same
/^v\d+\.\d+\.\d+$/ validation and descending semver sort before building the
claude paths.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aee3a63 and e552099.

📒 Files selected for processing (1)
  • apps/frontend/src/main/cli-tool-manager.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/cli-tool-manager.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/cli-tool-manager.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/cli-tool-manager.ts
🧠 Learnings (1)
📓 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.
🧬 Code graph analysis (1)
apps/frontend/src/main/cli-tool-manager.ts (2)
apps/frontend/src/main/env-utils.ts (3)
  • existsAsync (29-36)
  • findExecutable (252-273)
  • findExecutableAsync (411-430)
apps/frontend/src/shared/types/cli.ts (1)
  • ToolDetectionResult (12-25)
⏰ 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). (2)
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (6)
apps/frontend/src/main/cli-tool-manager.ts (6)

154-181: LGTM!

Good coverage of Windows installation methods (official installer, npm global, Scoop, Chocolatey, Program Files) and simplified Unix paths. The comment about nvm-windows being added dynamically is helpful for maintainability.


284-316: LGTM!

The registry output parsing and environment variable expansion are correctly implemented. The regex pattern handles both REG_SZ and REG_EXPAND_SZ types, and undefined environment variables are preserved (correct fallback behavior).


383-411: LGTM!

The extension search order (.exe, .cmd, .bat, then extensionless) correctly prioritizes Windows-native executables over potential bash/shell scripts, consistent with findExecutable in env-utils.ts.


948-1062: LGTM!

The updated detection priority correctly addresses the race condition by:

  1. Checking Windows Registry PATH first (which GUI apps don't inherit)
  2. Moving user configuration to step 2 as a fallback
  3. Adding nvm-windows path detection

The detection flow is well-structured with appropriate platform guards.


1490-1504: Detection priority mirrors sync version correctly.

The async implementation maintains the same detection priority as the sync version. Note that the blocking issue with findClaudeInRegistryPathAsync (noted earlier) affects this code path as well.


2082-2100: LGTM!

Clean export wrapper with helpful documentation and examples.

…ndyMik90#918)

* fix(frontend): prevent "Render frame was disposed" crash (ACS-211)

Add safeSendToRenderer helper that validates frame state before IPC sends.
Prevents app crash when renderer frames are disposed during heavy agent output.

Fixes AndyMik90#211

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(utils): replace setInterval with timestamp-based cooldown, add \r\n support

- Replace setInterval-based cooldown with timestamp Map approach to avoid timer leaks
- Add isWithinCooldown() and recordWarning() helper functions
- Optionally prune old entries when Map exceeds 100 entries
- Update parseEnvFile to handle Windows \r\n line endings with /\r?\n/ regex

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(utils): enforce hard cap of 100 entries in pruning logic

- First remove expired entries (outside cooldown period)
- If still over 100 entries, remove oldest by insertion order
- Ensures Map never exceeds 100 entries even during heavy load

Signed-off-by: StillKnotKnown <[email protected]>

* test: fix module-level state issue in pruning tests

- Add _clearWarnTimestampsForTest() helper to clear module-level Map
- Call clear in parent beforeEach to ensure clean state for each test
- Simplify pruning tests to avoid complex cooldown timing issues
- All 28 tests now pass

* fix: update generation-handlers.ts to use safeSendToRenderer

Addresses finding NEW-003 from follow-up review:
- Import safeSendToRenderer from '../utils'
- Replace all 5 direct webContents.send() calls with safeSendToRenderer
- Add getMainWindow wrapper for each function

This ensures ideation generation IPC messages are protected from
"Render frame was disposed" crashes.

Related: ACS-211

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
@VDT-91
Copy link
Author

VDT-91 commented Jan 12, 2026

Addressed CodeRabbit Review Feedback

Pushed fixes for the review comments:

✅ Fixed Issues

  1. Async function uses sync registry call (Major)

    • Created getWindowsRegistryPathAsync() using execAsync
    • Updated findClaudeInRegistryPathAsync() to use it
    • Now fully non-blocking
  2. Empty string extension (Major)

    • Removed '' from extensions array
    • Updated JSDoc to accurately describe behavior
    • Now only checks: .exe, .cmd, .bat
  3. Duplicated sorting logic (Nitpick)

    • Refactored getNvmWindowsPaths() to reuse sortNvmVersionDirs()
    • Added proper semver validation (filters invalid dirs like vbackup)

❌ Not Changed (Verified Correct)

  1. PATH ordering - CodeRabbit suggested User PATH before System PATH, but this is incorrect. Per SS64 Windows Environment Variables:

    "The User path is appended to the system path"

    Windows constructs PATH as: System PATH + User PATH. Our implementation is correct.

All changes verified with npm run typecheck

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e552099 and cbe5a65.

📒 Files selected for processing (1)
  • apps/frontend/src/main/cli-tool-manager.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/cli-tool-manager.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/cli-tool-manager.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/cli-tool-manager.ts
🧠 Learnings (1)
📓 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.
🧬 Code graph analysis (1)
apps/frontend/src/main/cli-tool-manager.ts (2)
apps/frontend/src/main/env-utils.ts (3)
  • existsAsync (29-36)
  • findExecutable (252-273)
  • findExecutableAsync (411-430)
apps/frontend/src/shared/types/cli.ts (1)
  • ToolDetectionResult (12-25)
⏰ 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). (2)
  • GitHub Check: CodeQL (python)
  • GitHub Check: CodeQL (javascript-typescript)
🔇 Additional comments (8)
apps/frontend/src/main/cli-tool-manager.ts (8)

154-185: Comprehensive Windows path coverage for Claude CLI detection.

The expanded path arrays cover multiple installation methods (official installer, npm, Scoop, Chocolatey, Program Files) which significantly improves detection reliability. The separation of windowsPaths and unixPaths with platform-based selection is clean.

Note: The hardcoded C:\ paths (lines 168-172) assume the system drive is C:. This is acceptable since the majority of Windows installations use C: and the detection has multiple fallbacks.


284-294: LGTM!

The regex correctly parses both REG_SZ and REG_EXPAND_SZ value types from registry output. The error detection via includes('ERROR:') is sufficient for this use case.


308-316: LGTM!

The environment variable expansion correctly handles the %VAR% pattern and gracefully preserves unresolved variables.


438-507: LGTM!

Both sync and async implementations correctly search for Claude executables in registry PATH directories. The extension priority (.exe, .cmd, .bat) is sensible, and the error handling for inaccessible paths is appropriate.


519-548: Good integration with nvm-windows.

The function correctly enumerates nvm-windows version directories and reuses sortNvmVersionDirs for proper semver validation and sorting. This ensures the newest Node version is checked first.


1004-1015: Core fix for Windows GUI launch race condition.

The Windows Registry PATH detection at position #1 correctly addresses the root cause: Windows GUI-launched Electron apps don't inherit the shell's PATH environment. Reading from the registry (HKLM\...\Environment\Path and HKCU\Environment\Path) provides the authoritative Windows PATH that includes user-installed CLIs.

This is the key fix that enables Claude CLI detection on first startup without waiting for settings to load.


1546-1557: LGTM!

The async detection correctly uses findClaudeInRegistryPathAsync which internally uses execAsync for non-blocking registry reads. This maintains consistency with the sync version while being safe for the Electron main process.


1066-1076: Good nvm-windows fallback.

The nvm-windows path enumeration at position #6 provides a fallback for scenarios where Claude is installed via npm in an nvm-managed Node.js environment that might not be reflected in the registry PATH. The newest Node version is checked first due to sortNvmVersionDirs.

…CS-209) (AndyMik90#915)

* fix(core): implement atomic JSON writes to prevent file corruption (ACS-209)

- Add write_json_atomic() utility using temp file + os.replace()
- Add async_save() to ImplementationPlan for non-blocking I/O
- Update planner.py to use async_save() in async context
- Add 'error' status to TaskStatus for corrupted files
- Enhance ProjectStore error handling to surface parse errors
- Add recovery CLI utility (cli/recovery.py) for detecting/fixing corrupted files

This fixes JSON parse errors that caused tasks to be silently skipped
when implementation_plan.json was corrupted during crashes/interrupts.

* fix(i18n): add error column to task status constants and translations

- Add 'error' to TASK_STATUS_COLUMNS array
- Add 'error' label and color to TASK_STATUS_LABELS and TASK_STATUS_COLORS
- Add 'columns.error' translation key to en/tasks.json and fr/tasks.json

This fixes TypeScript errors in KanbanBoard.tsx where the Record type
was missing the 'error' status that was added to TaskStatus type.

* refactor: improve code quality and add i18n support for error messages

Backend improvements:
- Fix duplicate JSON check in recovery.py (remove redundant plan_file check)
- Update find_specs_dir return type to Path (always returns valid path)
- Replace deprecated asyncio.get_event_loop() with asyncio.get_running_loop()
- Use functools.partial for cleaner async_save implementation

Frontend improvements:
- Add TaskErrorInfo type for structured error information
- Update project-store.ts to use errorInfo for i18n-compatible error messages
- Tighten typing of TASK_STATUS_LABELS and TASK_STATUS_COLORS to use TaskStatusColumn
- Add error column to KanbanBoard grouped tasks initialization
- Add en/fr errors.json translation files for parse error messages

* docs: add errors.json to i18n translation namespaces

- Document new errors.json namespace for error messages
- Add example showing interpolation/substitution pattern for dynamic error content

* refactor: typing improvements, i18n fixes, and error UX enhancements

Backend typing:
- Add explicit return type hint (-> None) to main() in recovery.py
- Add explicit return type hint (-> None) to async_save() in plan.py
- Make recovery.py exit with code 1 when corrupted files are detected

Error handling improvements:
- Include specId in errorInfo meta for better error context
- Cap error message length at 500 characters to prevent bloat
- Update error translation keys to include specId substitution

Frontend improvements:
- Conditionally add reviewReason/errorInfo to task objects only when defined
- Add 'error' case to KanbanBoard empty state with AlertCircle icon
- Fix hardcoded "Refreshing..."/"Refresh Tasks" strings to use i18n

i18n additions:
- Add emptyError/emptyErrorHint to en/fr tasks.json
- Add refreshing/refreshTasks to en/fr translation files

* refactor: code quality improvements

- Remove error truncation in recovery.py (show full error for debugging)
- Extract duplicate timestamp/status update logic to _update_timestamps_and_status() helper
- Fix MD031 in CLAUDE.md (add blank line before fenced code block)

* refactor: code quality improvements

- Remove error truncation in recovery.py (show full error for debugging)
- Extract duplicate timestamp/status update logic to _update_timestamps_and_status() helper
- Fix MD031 in CLAUDE.md (add blank line before fenced code block)

* refactor: naming and typing improvements

- Update docstring examples in recovery.py (--fix -> --delete)
- Rename delete_corrupted_file to backup_corrupted_file for clarity
- Add return type annotation -> None to save() method

* fix: add error status handling to TaskCard

- Add 'error' case to getStatusBadgeVariant() returning 'destructive'
- Add 'error' case to getStatusLabel() returning t('columns.error')
- Start/stop buttons already exclude error tasks (backlog/in_progress only)

* fix: address PR review feedback

Backend changes:
- recovery.py: Change [DELETE] to [BACKUP] in output message to match operation
- recovery.py: Replace startswith with is_relative_to for proper path validation
- recovery.py: Handle existing .corrupted backup files with unique timestamp suffix
- file_utils.py: Add Iterator[IO[str]] return type annotation to atomic_write

Frontend changes:
- KanbanBoard.tsx: Use column-error CSS class instead of inline border-t-destructive
- globals.css: Add .column-error rule with destructive color for consistency
- tasks.json: Add top-level refreshTasks translation key for en/fr locales

* fix: address follow-up review findings

Backend changes:
- file_utils.py: Handle binary mode correctly (encoding=None for 'b' in mode)
- file_utils.py: Change return type to Iterator[IO] for broader type support
- file_utils.py: Add docstring note about binary mode support
- plan.py: Fix async_save to restore state on write failure (captures timestamps)

Frontend changes:
- project-store.ts: Add 'error' to statusMap to preserve error status
- project-store.ts: Add early return for 'error' status like 'done'/'pr_created'
- task-store.ts: Allow recovery from error status to backlog/in_progress
- task-store.ts: Allow transitions to error without completion validation

* fix: address follow-up review findings

Backend changes:
- file_utils.py: Handle binary mode correctly (encoding=None for 'b' in mode)
- file_utils.py: Change return type to Iterator[IO] for broader type support
- file_utils.py: Add docstring note about binary mode support
- plan.py: Fix async_save to restore state on write failure (captures timestamps)

Frontend changes:
- project-store.ts: Add 'error' to statusMap to preserve error status
- project-store.ts: Add early return for 'error' status like 'done'/'pr_created'
- task-store.ts: Allow recovery from error status to backlog/in_progress
- task-store.ts: Allow transitions to error without completion validation

* fix: address third follow-up review findings

Backend changes:
- recovery.py: Change spec_dir.glob to spec_dir.rglob for recursive JSON scan
- file_utils.py: Fix fd leak when os.fdopen raises (close fd and unlink tmp_path)
- plan.py: Capture full state with to_dict() for robust rollback in async_save

* fix: address final review quality suggestions

Backend changes:
- plan.py: Add NOTE comment about rollback fields maintenance
- file_utils.py: Add logging.warning for temp file cleanup failures

* fix: address final review quality suggestions

Backend changes:
- plan.py: Add NOTE comment about rollback fields maintenance
- file_utils.py: Add logging.warning for temp file cleanup failures

* fix: address final review quality suggestions

Backend changes:
- plan.py: Add NOTE comment about rollback fields maintenance
- file_utils.py: Add logging.warning for temp file cleanup failures

* fix: include stack trace in temp file cleanup failure logging

Add exc_info=True to logging.warning call when temp file cleanup fails.
This captures the full stack trace for better postmortem debugging of
orphaned temp files.

---------

Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>
@VDT-91
Copy link
Author

VDT-91 commented Jan 12, 2026

Latest Commit: Fix Child Process PATH Environment

This commit (b6eddf8) addresses an issue discovered during testing where Claude CLI was successfully found via Registry PATH, but validation failed because claude.cmd is a wrapper script that calls node, and node wasn't in the child process's PATH.

Root Cause

When Electron runs claude.cmd --version to validate the CLI, it spawns a child process. The previous fix only read the Registry PATH for finding Claude, but didn't pass it to child processes during validation/execution.

Solution

  • Centralized Registry PATH helpers in env-utils.ts (previously duplicated in cli-tool-manager.ts)
  • Updated getAugmentedEnv() and getAugmentedEnvAsync() to include Windows Registry PATH
  • Added caching for Registry PATH queries to avoid repeated registry reads
  • All child processes now have access to the full Windows PATH

Testing

Tested by starting the app from a fresh command prompt (not inheriting shell PATH):

[Claude CLI] Found via Registry PATH: C:\Users\sondree\AppData\Roaming\npm\claude.cmd
[Claude Code] Detection result: {
  "found": true,
  "path": "C:\Users\sondree\AppData\Roaming\npm\claude.cmd",
  "version": "2.1.5",
  "source": "system-path",
  "message": "Using Claude CLI from Windows PATH: ..."
}

Before this fix, validation would fail with: '"node"' is not recognized as an internal or external command

Files Changed

  • apps/frontend/src/main/env-utils.ts - Added Registry PATH helpers and updated env augmentation
  • apps/frontend/src/main/cli-tool-manager.ts - Now imports from env-utils.ts, removed duplicates

for (const nvmPath of nvmWindowsPaths) {
if (existsSync(nvmPath)) {
const validation = this.validateClaude(nvmPath);
const result = buildClaudeDetectionResult(nvmPath, validation, 'nvm', 'Using nvm-windows Claude CLI');

Check warning

Code scanning / CodeQL

Indirect uncontrolled command line Medium

This command depends on an unsanitized
environment variable
.
for (const nvmPath of nvmWindowsPaths) {
if (existsSync(nvmPath)) {
const validation = this.validateClaude(nvmPath);
const result = buildClaudeDetectionResult(nvmPath, validation, 'nvm', 'Using nvm-windows Claude CLI');

Check warning

Code scanning / CodeQL

Shell command built from environment values Medium

This shell command depends on an uncontrolled
file name
.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @apps/frontend/src/main/env-utils.ts:
- Around line 16-20: Tests fail because the child_process mock used by
env-utils.ts omits the exec export which env-utils imports and uses; update the
vi.mock for 'child_process' in the test (used by
apps/frontend/src/main/__tests__/env-handlers-claude-cli.test.ts) to include an
exec implementation that mirrors execFile mock behavior (accepting (cmd, opts,
cb) signature, normalizing optional callback parameter, invoking the callback
asynchronously with (null, '', '') and returning a stubbed object with on
method) so calls to exec from env-utils.ts succeed in tests.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cbe5a65 and b6eddf8.

📒 Files selected for processing (2)
  • apps/frontend/src/main/cli-tool-manager.ts
  • apps/frontend/src/main/env-utils.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/cli-tool-manager.ts
  • apps/frontend/src/main/env-utils.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/cli-tool-manager.ts
  • apps/frontend/src/main/env-utils.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/cli-tool-manager.ts
  • apps/frontend/src/main/env-utils.ts
🧠 Learnings (1)
📓 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.
🧬 Code graph analysis (1)
apps/frontend/src/main/cli-tool-manager.ts (1)
apps/frontend/src/main/env-utils.ts (5)
  • getWindowsRegistryPath (106-154)
  • getWindowsRegistryPathAsync (164-224)
  • existsAsync (30-37)
  • findExecutable (463-484)
  • findExecutableAsync (635-654)
🪛 GitHub Actions: CI
apps/frontend/src/main/cli-tool-manager.ts

[error] 298-300: Find Claude in registry path failed due to missing mock export getWindowsRegistryPath. Tests referencing Windows registry path resolution cannot proceed.

🪛 GitHub Check: test-frontend
apps/frontend/src/main/cli-tool-manager.ts

[failure] 338-338: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI async Windows where.exe detection > should handle async where.exe errors gracefully
Error: [vitest] No "getWindowsRegistryPathAsync" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPathAsync src/main/cli-tool-manager.ts:338:30
❯ CLIToolManager.detectClaudeAsync src/main/cli-tool-manager.ts:1404:40
❯ CLIToolManager.detectToolPathAsync src/main/cli-tool-manager.ts:1193:21
❯ CLIToolManager.getToolPathAsync src/main/cli-tool-manager.ts:1166:31
❯ Module.getToolPathAsync src/main/cli-tool-manager.ts:2030:25
❯ src/main/tests/cli-tool-manager.test.ts:736:26


[failure] 338-338: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI async Windows where.exe detection > should detect Claude CLI via where.exe asynchronously
Error: [vitest] No "getWindowsRegistryPathAsync" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPathAsync src/main/cli-tool-manager.ts:338:30
❯ CLIToolManager.detectClaudeAsync src/main/cli-tool-manager.ts:1404:40
❯ CLIToolManager.detectToolPathAsync src/main/cli-tool-manager.ts:1193:21
❯ CLIToolManager.getToolPathAsync src/main/cli-tool-manager.ts:1166:31
❯ Module.getToolPathAsync src/main/cli-tool-manager.ts:2030:25
❯ src/main/tests/cli-tool-manager.test.ts:720:11


[failure] 298-298: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI Windows where.exe detection > should handle where.exe execution errors gracefully
Error: [vitest] No "getWindowsRegistryPath" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPath src/main/cli-tool-manager.ts:298:24
❯ CLIToolManager.detectClaude src/main/cli-tool-manager.ts:862:34
❯ CLIToolManager.detectToolPath src/main/cli-tool-manager.ts:492:21
❯ CLIToolManager.getToolInfo src/main/cli-tool-manager.ts:1892:17
❯ Module.getToolInfo src/main/cli-tool-manager.ts:1968:25
❯ src/main/tests/cli-tool-manager.test.ts:686:20


[failure] 298-298: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI Windows where.exe detection > should prefer .cmd/.exe paths when where.exe returns multiple results
Error: [vitest] No "getWindowsRegistryPath" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPath src/main/cli-tool-manager.ts:298:24
❯ CLIToolManager.detectClaude src/main/cli-tool-manager.ts:862:34
❯ CLIToolManager.detectToolPath src/main/cli-tool-manager.ts:492:21
❯ CLIToolManager.getToolInfo src/main/cli-tool-manager.ts:1892:17
❯ Module.getToolInfo src/main/cli-tool-manager.ts:1968:25
❯ src/main/tests/cli-tool-manager.test.ts:668:20


[failure] 298-298: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI Windows where.exe detection > should fallback to platform paths if where.exe fails
Error: [vitest] No "getWindowsRegistryPath" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPath src/main/cli-tool-manager.ts:298:24
❯ CLIToolManager.detectClaude src/main/cli-tool-manager.ts:862:34
❯ CLIToolManager.detectToolPath src/main/cli-tool-manager.ts:492:21
❯ CLIToolManager.getToolInfo src/main/cli-tool-manager.ts:1892:17
❯ Module.getToolInfo src/main/cli-tool-manager.ts:1968:25
❯ src/main/tests/cli-tool-manager.test.ts:647:20


[failure] 298-298: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI Windows where.exe detection > should validate Claude CLI before returning where.exe path
Error: [vitest] No "getWindowsRegistryPath" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPath src/main/cli-tool-manager.ts:298:24
❯ CLIToolManager.detectClaude src/main/cli-tool-manager.ts:862:34
❯ CLIToolManager.detectToolPath src/main/cli-tool-manager.ts:492:21
❯ CLIToolManager.getToolInfo src/main/cli-tool-manager.ts:1892:17
❯ Module.getToolInfo src/main/cli-tool-manager.ts:1968:25
❯ src/main/tests/cli-tool-manager.test.ts:622:20


[failure] 298-298: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI Windows where.exe detection > should detect Claude CLI via where.exe when not in PATH
Error: [vitest] No "getWindowsRegistryPath" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPath src/main/cli-tool-manager.ts:298:24
❯ CLIToolManager.detectClaude src/main/cli-tool-manager.ts:862:34
❯ CLIToolManager.detectToolPath src/main/cli-tool-manager.ts:492:21
❯ CLIToolManager.getToolInfo src/main/cli-tool-manager.ts:1892:17
❯ Module.getToolInfo src/main/cli-tool-manager.ts:1968:25
❯ src/main/tests/cli-tool-manager.test.ts:573:20


[failure] 298-298: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI NVM detection > Platform-specific path detection > should detect Claude CLI in Windows AppData npm global path
Error: [vitest] No "getWindowsRegistryPath" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPath src/main/cli-tool-manager.ts:298:24
❯ CLIToolManager.detectClaude src/main/cli-tool-manager.ts:862:34
❯ CLIToolManager.detectToolPath src/main/cli-tool-manager.ts:492:21
❯ CLIToolManager.getToolInfo src/main/cli-tool-manager.ts:1892:17
❯ Module.getToolInfo src/main/cli-tool-manager.ts:1968:25
❯ src/main/tests/cli-tool-manager.test.ts:341:22


[failure] 298-298: src/main/tests/cli-tool-manager.test.ts > cli-tool-manager - Claude CLI NVM detection > NVM path detection on Unix/Linux/macOS > should skip NVM path detection on Windows
Error: [vitest] No "getWindowsRegistryPath" export is defined on the "../env-utils" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("../env-utils"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ findClaudeInRegistryPath src/main/cli-tool-manager.ts:298:24
❯ CLIToolManager.detectClaude src/main/cli-tool-manager.ts:862:34
❯ CLIToolManager.detectToolPath src/main/cli-tool-manager.ts:492:21
❯ CLIToolManager.getToolInfo src/main/cli-tool-manager.ts:1892:17
❯ Module.getToolInfo src/main/cli-tool-manager.ts:1968:25
❯ src/main/tests/cli-tool-manager.test.ts:210:22

apps/frontend/src/main/env-utils.ts

[failure] 20-20: src/main/tests/env-handlers-claude-cli.test.ts
Error: [vitest] No "exec" export is defined on the "child_process" mock. Did you forget to return it from "vi.mock"?
If you need to partially mock a module, you can use "importOriginal" helper inside:

vi.mock(import("child_process"), async (importOriginal) => {
const actual = await importOriginal()
return {
...actual,
// your mocked methods
}
})

❯ src/main/env-utils.ts:20:29
❯ src/main/ipc-handlers/env-handlers.ts:13:1

⏰ 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). (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)
🔇 Additional comments (13)
apps/frontend/src/main/cli-tool-manager.ts (7)

166-197: LGTM! Comprehensive Windows path coverage.

The updated getClaudeDetectionPaths now includes paths for multiple Windows installation methods (official installer, npm global, Scoop, Chocolatey, Program Files). The separation of windowsPaths and unixPaths with platform selection is clean.


293-322: LGTM! Registry-based Claude detection is well-implemented.

The function correctly reads the true Windows PATH from Registry and searches for Claude with appropriate extensions. Platform guard and error handling are in place.


332-362: LGTM! Async variant properly uses non-blocking operations.

The async version correctly uses getWindowsRegistryPathAsync() and existsAsync() to avoid blocking the Electron main process.


374-403: LGTM! nvm-windows path enumeration is correct.

The function properly enumerates Claude paths from nvm-windows installations. Reusing sortNvmVersionDirs for semver validation ensures consistency with Unix NVM handling. The sync directory read is acceptable here since it's reading a small local directory.


859-870: LGTM! Registry PATH prioritized correctly for Windows GUI apps.

The detection now correctly checks Windows Registry PATH first, which contains the true system PATH that GUI apps don't inherit from shell. This directly addresses the race condition fix described in the PR objectives.


921-931: LGTM! nvm-windows detection integrated correctly.

The nvm-windows paths are checked after system PATH methods but before Unix NVM and platform paths, which is appropriate for Windows-specific detection.


29-41: Missing mocks for registry functions need verification against actual test failures.

The main file imports getWindowsRegistryPath and getWindowsRegistryPathAsync from env-utils (lines 39-40), and these are used in the exported functions findClaudeInRegistryPath() and findClaudeInRegistryPathAsync(). However, these functions are not currently imported or tested in the test file. The test file only imports and tests: getToolInfo, getToolPathAsync, clearToolCache, getClaudeDetectionPaths, sortNvmVersionDirs, and buildClaudeDetectionResult.

Additionally, parseRegOutput and expandWindowsEnvVars are imported in the main file but not actually used anywhere in the code—they appear to be unused imports.

Confirm whether the referenced "7 test failures" actually occur, and clarify which test cases are affected by these missing mocks.

apps/frontend/src/main/env-utils.ts (6)

60-70: LGTM! Robust registry output parsing.

The function correctly handles both REG_SZ and REG_EXPAND_SZ types and checks for error responses. The regex properly captures the PATH value.


84-92: LGTM! Safe environment variable expansion.

The function correctly expands %VAR% patterns while preserving unmatched variables (returns original match if env var not found), which is defensive against missing variables.


106-154: LGTM! Well-implemented sync Registry PATH reader.

The function properly reads both system (HKLM) and user (HKCU) PATH with:

  • Session-scoped caching to avoid repeated registry queries
  • Graceful fallback when one registry read fails
  • Proper environment variable expansion
  • Reasonable timeout (5000ms)

164-224: LGTM! Async version with proper concurrency handling.

The promise-based deduplication pattern (lines 174-177) correctly prevents concurrent registry calls when multiple callers request the PATH simultaneously. The finally block appropriately clears the promise cache.


407-418: LGTM! Registry PATH correctly integrated into environment augmentation.

The Registry PATH is prepended to give it priority over any inherited PATH, which is the correct behavior for Windows GUI apps. The conditional merge handles the case when currentPath is empty.


577-588: LGTM! Async version mirrors sync behavior correctly.

Uses getWindowsRegistryPathAsync() for non-blocking Registry access while maintaining the same prepending logic.

@VDT-91
Copy link
Author

VDT-91 commented Jan 12, 2026

CI Fix: Added Mock Functions for Registry PATH Helpers

The test-frontend CI was failing because the cli-tool-manager.test.ts mocks env-utils module, but didn't include the new exports:

  • getWindowsRegistryPath
  • getWindowsRegistryPathAsync

Added these to the mock with vi.fn(() => null) and vi.fn(() => Promise.resolve(null)) to return null (avoiding actual registry reads in tests).

The cli-tool-manager tests now pass. The remaining test failures in the CI are pre-existing issues in claude-integration-handler.test.ts related to Windows path separators - unrelated to this PR.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @apps/frontend/src/main/cli-tool-manager.ts:
- Around line 291-320: The Registry-derived PATH entries in
findClaudeInRegistryPath are not security-validated and one detection log uses
console.log; update the function to call the existing isSecurePath(...) on each
directory (or on the resolved candidatePath) before accepting it and skip any
insecure entries, and replace the console.log call with console.warn to match
the file's logging convention; use the same helpers already referenced
(getWindowsRegistryPath, path.join, existsSync) and ensure insecure candidates
are ignored and, if desired, emit a console.warn about skipping insecure
registry PATH entries.
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b6eddf8 and ec3ef2a.

📒 Files selected for processing (2)
  • apps/frontend/src/main/__tests__/cli-tool-manager.test.ts
  • apps/frontend/src/main/cli-tool-manager.ts
🧰 Additional context used
📓 Path-based instructions (3)
apps/frontend/src/**/*.{ts,tsx,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Always use i18n translation keys for all user-facing text in the frontend instead of hardcoded strings

Files:

  • apps/frontend/src/main/__tests__/cli-tool-manager.test.ts
  • apps/frontend/src/main/cli-tool-manager.ts
apps/frontend/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use useTranslation() hook with namespace prefixes (e.g., 'navigation:items.key') for accessing translation strings in React components

Files:

  • apps/frontend/src/main/__tests__/cli-tool-manager.test.ts
  • apps/frontend/src/main/cli-tool-manager.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/__tests__/cli-tool-manager.test.ts
  • apps/frontend/src/main/cli-tool-manager.ts
🧠 Learnings (1)
📓 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.
⏰ 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). (2)
  • GitHub Check: CodeQL (javascript-typescript)
  • GitHub Check: CodeQL (python)
🔇 Additional comments (9)
apps/frontend/src/main/cli-tool-manager.ts (8)

29-39: LGTM! Imports are well-organized and aligned with the new Registry PATH functionality.


164-195: LGTM! Comprehensive Windows path coverage.

The detection paths cover multiple installation methods (npm, Scoop, Chocolatey, official installer) which addresses the various ways users might have Claude CLI installed on Windows.


330-360: Same considerations as sync version apply here.

The async variant mirrors the sync logic correctly. Apply the same security validation and logging consistency improvements suggested for findClaudeInRegistryPath.


372-401: LGTM! Good reuse of sortNvmVersionDirs for consistent semver validation.

The implementation correctly filters out invalid version directories (e.g., vbackup, vold) by reusing the existing semver validation logic. The fallback for APPDATA and multiple extension variants ensure robust detection across nvm-windows configurations.


857-868: LGTM! Registry PATH detection correctly prioritized for Windows GUI launch fix.

This directly addresses the PR objective: GUI apps don't inherit the shell's PATH, so reading from Registry ensures Claude CLI is found on Windows desktop/Start Menu launches.


919-929: LGTM! nvm-windows detection properly integrated into the flow.


1399-1410: LGTM! Async Registry PATH detection mirrors sync implementation.

The async variant properly uses findClaudeInRegistryPathAsync and validateClaudeAsync to avoid blocking the Electron main process during detection.


1461-1471: LGTM! Async nvm-windows detection properly uses non-blocking operations.

apps/frontend/src/main/__tests__/cli-tool-manager.test.ts (1)

129-135: LGTM! Mocks correctly isolate tests from Windows Registry operations.

The added mocks for existsAsync and the Registry PATH helpers ensure unit tests don't perform actual registry reads. The null/identity return values appropriately simulate "registry unavailable" conditions. All mocked functions (parseRegOutput, getWindowsRegistryPath, getWindowsRegistryPathAsync, expandWindowsEnvVars, and existsAsync) are exported from env-utils.ts and are necessary for proper test isolation.

Comment on lines +291 to +320
export function findClaudeInRegistryPath(): string | null {
if (process.platform !== 'win32') {
return null;
}

const registryPath = getWindowsRegistryPath();
if (!registryPath) {
return null;
}

const pathDirs = registryPath.split(';').filter(Boolean);
// Standard Windows executable extensions - checked in order of priority
const extensions = ['.exe', '.cmd', '.bat'];

for (const dir of pathDirs) {
for (const ext of extensions) {
const candidatePath = path.join(dir, `claude${ext}`);
try {
if (existsSync(candidatePath)) {
console.log(`[Claude CLI] Found via Registry PATH: ${candidatePath}`);
return candidatePath;
}
} catch {
// Skip inaccessible paths
}
}
}

return null;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

Consider security validation for Registry PATH entries.

The user-configured path validation uses isSecurePath() (line 876), but paths discovered from Registry PATH are not validated. While the registry is generally trusted, a compromised PATH entry could lead to executing unintended binaries.

Additionally, Line 310 uses console.log while the rest of the file uses console.warn for logging detection messages. Consider using console.warn for consistency.

♻️ Suggested security check and logging consistency
         try {
           if (existsSync(candidatePath)) {
+            if (!isSecurePath(candidatePath)) {
+              console.warn(`[Claude CLI] Registry PATH entry failed security validation, skipping: ${candidatePath}`);
+              continue;
+            }
-            console.log(`[Claude CLI] Found via Registry PATH: ${candidatePath}`);
+            console.warn(`[Claude CLI] Found via Registry PATH: ${candidatePath}`);
             return candidatePath;
           }
📝 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.

Suggested change
export function findClaudeInRegistryPath(): string | null {
if (process.platform !== 'win32') {
return null;
}
const registryPath = getWindowsRegistryPath();
if (!registryPath) {
return null;
}
const pathDirs = registryPath.split(';').filter(Boolean);
// Standard Windows executable extensions - checked in order of priority
const extensions = ['.exe', '.cmd', '.bat'];
for (const dir of pathDirs) {
for (const ext of extensions) {
const candidatePath = path.join(dir, `claude${ext}`);
try {
if (existsSync(candidatePath)) {
console.log(`[Claude CLI] Found via Registry PATH: ${candidatePath}`);
return candidatePath;
}
} catch {
// Skip inaccessible paths
}
}
}
return null;
}
export function findClaudeInRegistryPath(): string | null {
if (process.platform !== 'win32') {
return null;
}
const registryPath = getWindowsRegistryPath();
if (!registryPath) {
return null;
}
const pathDirs = registryPath.split(';').filter(Boolean);
// Standard Windows executable extensions - checked in order of priority
const extensions = ['.exe', '.cmd', '.bat'];
for (const dir of pathDirs) {
for (const ext of extensions) {
const candidatePath = path.join(dir, `claude${ext}`);
try {
if (existsSync(candidatePath)) {
if (!isSecurePath(candidatePath)) {
console.warn(`[Claude CLI] Registry PATH entry failed security validation, skipping: ${candidatePath}`);
continue;
}
console.warn(`[Claude CLI] Found via Registry PATH: ${candidatePath}`);
return candidatePath;
}
} catch {
// Skip inaccessible paths
}
}
}
return null;
}
🤖 Prompt for AI Agents
In @apps/frontend/src/main/cli-tool-manager.ts around lines 291 - 320, The
Registry-derived PATH entries in findClaudeInRegistryPath are not
security-validated and one detection log uses console.log; update the function
to call the existing isSecurePath(...) on each directory (or on the resolved
candidatePath) before accepting it and skip any insecure entries, and replace
the console.log call with console.warn to match the file's logging convention;
use the same helpers already referenced (getWindowsRegistryPath, path.join,
existsSync) and ensure insecure candidates are ignored and, if desired, emit a
console.warn about skipping insecure registry PATH entries.

@VDT-91
Copy link
Author

VDT-91 commented Jan 12, 2026

CI Fix #2: Added exec/execSync mocks to env-handlers-claude-cli tests

Another test file (env-handlers-claude-cli.test.ts) also needed the exec and execSync mocks added to its child_process mock, since env-utils.ts now imports exec for the async Registry PATH operations.

VDT-91 and others added 8 commits January 12, 2026 13:43
… detection

Windows GUI apps (like Electron) don't inherit the shell's PATH environment
variable. This causes "Claude CLI not found" errors even when Claude is
correctly installed and accessible from terminal.

Changes:
- Add parseRegOutput() to parse Windows Registry output
- Add expandWindowsEnvVars() to expand %USERPROFILE%, %APPDATA% etc.
- Add getWindowsRegistryPath() to read TRUE PATH from HKLM + HKCU
- Add findClaudeInRegistryPath() and async variant to search Registry PATH
- Add getNvmWindowsPaths() for nvm-windows installation support
- Update getClaudeDetectionPaths() with Scoop, Chocolatey, and more paths
- Update detectClaude() and detectClaudeAsync() with new detection order

New Windows Detection Order:
1. Windows Registry PATH (reads TRUE system PATH)
2. User configuration (fallback)
3. System PATH (augmented process.env.PATH)
4. where.exe lookup
5. nvm-windows paths
6. Known installation paths (npm, Scoop, Chocolatey, Program Files)

This fix addresses the root cause reported by users where Claude CLI was
installed and working in terminal but not detected by the Electron app.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…tection

Changes based on CodeRabbit review:

1. Create getWindowsRegistryPathAsync() - New async version using execAsync
   instead of execSync to avoid blocking the event loop in async contexts.

2. Update findClaudeInRegistryPathAsync() - Now uses getWindowsRegistryPathAsync()
   for fully non-blocking Windows Registry PATH detection.

3. Remove empty string from extensions array - The '' extension contradicted
   the JSDoc and could match non-executable files. Now only checks standard
   Windows extensions: .exe, .cmd, .bat

4. Refactor getNvmWindowsPaths() - Reuses sortNvmVersionDirs() instead of
   duplicating version sorting logic. This also adds proper semver validation
   (filters out invalid dirs like 'vbackup', 'vold').

Verified against official documentation:
- Windows PATH ordering (System before User) is correct per Microsoft docs
- Node.js async best practices followed per Node.js documentation

Co-Authored-By: Claude Opus 4.5 <[email protected]>
When validating Claude CLI on Windows, the child process running
`claude.cmd --version` needs access to `node` which is also in the
Windows Registry PATH. This commit:

- Moves Registry PATH helpers to env-utils.ts for shared use
- Updates getAugmentedEnv() to include Windows Registry PATH
- Updates getAugmentedEnvAsync() similarly
- Adds caching for Registry PATH to avoid repeated registry queries
- Removes duplicate function definitions from cli-tool-manager.ts

This fixes the issue where Claude CLI was found via Registry PATH but
validation failed with "'node' is not recognized" error because the
wrapper script couldn't find node in the child process environment.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ndyMik90#918)

* fix(frontend): prevent "Render frame was disposed" crash (ACS-211)

Add safeSendToRenderer helper that validates frame state before IPC sends.
Prevents app crash when renderer frames are disposed during heavy agent output.

Fixes AndyMik90#211

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(utils): replace setInterval with timestamp-based cooldown, add \r\n support

- Replace setInterval-based cooldown with timestamp Map approach to avoid timer leaks
- Add isWithinCooldown() and recordWarning() helper functions
- Optionally prune old entries when Map exceeds 100 entries
- Update parseEnvFile to handle Windows \r\n line endings with /\r?\n/ regex

Signed-off-by: StillKnotKnown <[email protected]>

* refactor(utils): enforce hard cap of 100 entries in pruning logic

- First remove expired entries (outside cooldown period)
- If still over 100 entries, remove oldest by insertion order
- Ensures Map never exceeds 100 entries even during heavy load

Signed-off-by: StillKnotKnown <[email protected]>

* test: fix module-level state issue in pruning tests

- Add _clearWarnTimestampsForTest() helper to clear module-level Map
- Call clear in parent beforeEach to ensure clean state for each test
- Simplify pruning tests to avoid complex cooldown timing issues
- All 28 tests now pass

* fix: update generation-handlers.ts to use safeSendToRenderer

Addresses finding NEW-003 from follow-up review:
- Import safeSendToRenderer from '../utils'
- Replace all 5 direct webContents.send() calls with safeSendToRenderer
- Add getMainWindow wrapper for each function

This ensures ideation generation IPC messages are protected from
"Render frame was disposed" crashes.

Related: ACS-211

---------

Signed-off-by: StillKnotKnown <[email protected]>
Co-authored-by: StillKnotKnown <[email protected]>
…CS-209) (AndyMik90#915)

* fix(core): implement atomic JSON writes to prevent file corruption (ACS-209)

- Add write_json_atomic() utility using temp file + os.replace()
- Add async_save() to ImplementationPlan for non-blocking I/O
- Update planner.py to use async_save() in async context
- Add 'error' status to TaskStatus for corrupted files
- Enhance ProjectStore error handling to surface parse errors
- Add recovery CLI utility (cli/recovery.py) for detecting/fixing corrupted files

This fixes JSON parse errors that caused tasks to be silently skipped
when implementation_plan.json was corrupted during crashes/interrupts.

* fix(i18n): add error column to task status constants and translations

- Add 'error' to TASK_STATUS_COLUMNS array
- Add 'error' label and color to TASK_STATUS_LABELS and TASK_STATUS_COLORS
- Add 'columns.error' translation key to en/tasks.json and fr/tasks.json

This fixes TypeScript errors in KanbanBoard.tsx where the Record type
was missing the 'error' status that was added to TaskStatus type.

* refactor: improve code quality and add i18n support for error messages

Backend improvements:
- Fix duplicate JSON check in recovery.py (remove redundant plan_file check)
- Update find_specs_dir return type to Path (always returns valid path)
- Replace deprecated asyncio.get_event_loop() with asyncio.get_running_loop()
- Use functools.partial for cleaner async_save implementation

Frontend improvements:
- Add TaskErrorInfo type for structured error information
- Update project-store.ts to use errorInfo for i18n-compatible error messages
- Tighten typing of TASK_STATUS_LABELS and TASK_STATUS_COLORS to use TaskStatusColumn
- Add error column to KanbanBoard grouped tasks initialization
- Add en/fr errors.json translation files for parse error messages

* docs: add errors.json to i18n translation namespaces

- Document new errors.json namespace for error messages
- Add example showing interpolation/substitution pattern for dynamic error content

* refactor: typing improvements, i18n fixes, and error UX enhancements

Backend typing:
- Add explicit return type hint (-> None) to main() in recovery.py
- Add explicit return type hint (-> None) to async_save() in plan.py
- Make recovery.py exit with code 1 when corrupted files are detected

Error handling improvements:
- Include specId in errorInfo meta for better error context
- Cap error message length at 500 characters to prevent bloat
- Update error translation keys to include specId substitution

Frontend improvements:
- Conditionally add reviewReason/errorInfo to task objects only when defined
- Add 'error' case to KanbanBoard empty state with AlertCircle icon
- Fix hardcoded "Refreshing..."/"Refresh Tasks" strings to use i18n

i18n additions:
- Add emptyError/emptyErrorHint to en/fr tasks.json
- Add refreshing/refreshTasks to en/fr translation files

* refactor: code quality improvements

- Remove error truncation in recovery.py (show full error for debugging)
- Extract duplicate timestamp/status update logic to _update_timestamps_and_status() helper
- Fix MD031 in CLAUDE.md (add blank line before fenced code block)

* refactor: code quality improvements

- Remove error truncation in recovery.py (show full error for debugging)
- Extract duplicate timestamp/status update logic to _update_timestamps_and_status() helper
- Fix MD031 in CLAUDE.md (add blank line before fenced code block)

* refactor: naming and typing improvements

- Update docstring examples in recovery.py (--fix -> --delete)
- Rename delete_corrupted_file to backup_corrupted_file for clarity
- Add return type annotation -> None to save() method

* fix: add error status handling to TaskCard

- Add 'error' case to getStatusBadgeVariant() returning 'destructive'
- Add 'error' case to getStatusLabel() returning t('columns.error')
- Start/stop buttons already exclude error tasks (backlog/in_progress only)

* fix: address PR review feedback

Backend changes:
- recovery.py: Change [DELETE] to [BACKUP] in output message to match operation
- recovery.py: Replace startswith with is_relative_to for proper path validation
- recovery.py: Handle existing .corrupted backup files with unique timestamp suffix
- file_utils.py: Add Iterator[IO[str]] return type annotation to atomic_write

Frontend changes:
- KanbanBoard.tsx: Use column-error CSS class instead of inline border-t-destructive
- globals.css: Add .column-error rule with destructive color for consistency
- tasks.json: Add top-level refreshTasks translation key for en/fr locales

* fix: address follow-up review findings

Backend changes:
- file_utils.py: Handle binary mode correctly (encoding=None for 'b' in mode)
- file_utils.py: Change return type to Iterator[IO] for broader type support
- file_utils.py: Add docstring note about binary mode support
- plan.py: Fix async_save to restore state on write failure (captures timestamps)

Frontend changes:
- project-store.ts: Add 'error' to statusMap to preserve error status
- project-store.ts: Add early return for 'error' status like 'done'/'pr_created'
- task-store.ts: Allow recovery from error status to backlog/in_progress
- task-store.ts: Allow transitions to error without completion validation

* fix: address follow-up review findings

Backend changes:
- file_utils.py: Handle binary mode correctly (encoding=None for 'b' in mode)
- file_utils.py: Change return type to Iterator[IO] for broader type support
- file_utils.py: Add docstring note about binary mode support
- plan.py: Fix async_save to restore state on write failure (captures timestamps)

Frontend changes:
- project-store.ts: Add 'error' to statusMap to preserve error status
- project-store.ts: Add early return for 'error' status like 'done'/'pr_created'
- task-store.ts: Allow recovery from error status to backlog/in_progress
- task-store.ts: Allow transitions to error without completion validation

* fix: address third follow-up review findings

Backend changes:
- recovery.py: Change spec_dir.glob to spec_dir.rglob for recursive JSON scan
- file_utils.py: Fix fd leak when os.fdopen raises (close fd and unlink tmp_path)
- plan.py: Capture full state with to_dict() for robust rollback in async_save

* fix: address final review quality suggestions

Backend changes:
- plan.py: Add NOTE comment about rollback fields maintenance
- file_utils.py: Add logging.warning for temp file cleanup failures

* fix: address final review quality suggestions

Backend changes:
- plan.py: Add NOTE comment about rollback fields maintenance
- file_utils.py: Add logging.warning for temp file cleanup failures

* fix: address final review quality suggestions

Backend changes:
- plan.py: Add NOTE comment about rollback fields maintenance
- file_utils.py: Add logging.warning for temp file cleanup failures

* fix: include stack trace in temp file cleanup failure logging

Add exc_info=True to logging.warning call when temp file cleanup fails.
This captures the full stack trace for better postmortem debugging of
orphaned temp files.

---------

Co-authored-by: StillKnotKnown <[email protected]>
Co-authored-by: Andy <[email protected]>
Removes parseRegOutput and expandWindowsEnvVars imports that are
no longer used after moving Registry PATH helpers to env-utils.ts.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Adds mock functions for getWindowsRegistryPath and
getWindowsRegistryPathAsync to the env-utils mock in tests,
fixing test failures after moving these functions to env-utils.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Adds mock functions for exec and execSync to the child_process mock
in env-handlers-claude-cli.test.ts, fixing test failures after adding
exec import to env-utils.ts for Registry PATH async operations.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@VDT-91 VDT-91 force-pushed the fix/windows-claude-cli-detection-race branch from 90704f2 to 9ed758b Compare January 12, 2026 12:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.