Skip to content

Conversation

@VDT-91
Copy link
Contributor

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

Summary

Fixes Windows-specific issue where processes accumulate in Task Manager after closing Auto-Claude. This addresses issues #1252, #641, #607, and relates to the previously closed but unmerged PR #753.

Root Causes Fixed

# Issue File Fix
1 SIGTERM/SIGKILL ignored on Windows agent-process.ts Use taskkill /f /t to kill process trees
2 killAllProcesses() resolves immediately agent-process.ts Wait for process exit events with 10s timeout
3 PTY daemon never killed on shutdown pty-daemon-client.ts Kill daemon process in shutdown()
4 App-updater interval never cleared app-updater.ts Store interval ID and clear on quit

Changes

  • agent-process.ts: Windows-aware killProcess() using taskkill /f /t fallback after .kill(), and killAllProcesses() that properly waits for process exit events
  • pty-daemon-client.ts: Kill PTY daemon process on shutdown using platform-appropriate method
  • app-updater.ts: Store periodic check interval ID and export stopPeriodicUpdates() function
  • index.ts: Call stopPeriodicUpdates() in before-quit handler
  • subprocess-spawn.test.ts: Update tests to handle platform-specific kill behavior

Implementation Details

The fix follows the existing pattern from worktree-handlers.ts (lines 3033-3061) and uses the centralized platform abstraction (isWindows() from platform/index.ts) as documented in CLAUDE.md.

Windows behavior:

// Windows: .kill() then taskkill fallback (SIGTERM/SIGKILL are ignored)
agentProcess.process.kill();
spawn('taskkill', ['/pid', pid.toString(), '/f', '/t'], {
  stdio: 'ignore',
  detached: true
}).unref();

Unix behavior:

// Unix: SIGTERM then SIGKILL
agentProcess.process.kill('SIGTERM');
setTimeout(() => {
  agentProcess.process.kill('SIGKILL');
}, 5000);

Test plan

  • TypeScript compiles successfully
  • All frontend tests pass (with --no-file-parallelism)
  • All backend tests pass (1575 tests)
  • Build completes successfully (npm run build)
  • Windows packaging tested: npm run package:win builds successfully
  • Manual Windows testing: Verified no orphaned processes remain in Task Manager after closing the app

Manual Testing Steps Performed

  1. Built the app with npm run package:win
  2. Installed and ran the packaged app
  3. Opened terminals and started build tasks
  4. Closed the app (click X)
  5. Checked Task Manager → Details tab
  6. Confirmed no orphaned node.exe, python.exe, cmd.exe, pwsh.exe, or Auto-Claude.exe processes remain

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added ability to stop periodic update checks.
    • Introduced improved process termination handling across platforms.
  • Bug Fixes

    • Enhanced Windows Python environment stability with better startup configuration and library loading.
    • Improved cross-platform process shutdown behavior with platform-specific fallback mechanisms.
  • Tests

    • Added comprehensive test coverage for Python environment setup and process management.

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

VDT-91 and others added 5 commits January 17, 2026 11:25
Python 3.8+ changed DLL search behavior - os.add_dll_directory() is now
required for DLL resolution. PYTHONPATH alone doesn't work because:
1. .pth files are NOT processed when PYTHONPATH is set
2. pywin32_bootstrap.py (which calls os.add_dll_directory) never runs
3. pywintypes312.dll cannot be found without explicit DLL path setup

This fix adds a PYTHONSTARTUP bootstrap script that:
- Calls os.add_dll_directory() for pywin32_system32 before any imports
- Uses site.addsitedir() to properly process .pth files
- Adds pywin32_system32 to PATH as fallback

Changes:
- python-env-manager.ts: Add PYTHONSTARTUP and PATH configuration
- download-python.cjs: Generate bootstrap script during build
- Added comprehensive tests for the fix

Fixes AndyMik90#810, AndyMik90#861
May also fix AndyMik90#943, AndyMik90#656, AndyMik90#630, AndyMik90#853

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Changes based on PR AndyMik90#1005 review comments:

1. Add .pyd extension check to sysloader filter (coderabbitai)
   - More precise filtering to avoid matching unrelated files

2. Add comments documenting DLL duplication trade-off (coderabbitai)
   - Explains why DLLs are copied to 3 locations (~2MB extra)
   - Documents the reliability vs bundle size trade-off

3. Add sync comments between bootstrap script locations (gemini, coderabbitai)
   - download-python.cjs and python-env-manager.ts now reference each other
   - Ensures future maintainers know to keep them synchronized

4. Add warning log when PYTHONSTARTUP creation fails (coderabbitai)
   - Surfaces the failure so users know pywin32 fix may not work
   - Mentions PATH fallback limitation on Python 3.8+

5. Improve tests with Vitest best practices (coderabbitai)
   - Use vi.stubEnv instead of manual process.env mutation
   - Better PYTHONSTARTUP assertion logic
   - Integration test now uses actual generated content instead of duplicate

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace existsSync + writeFileSync pattern with atomic 'wx' flag approach
as recommended by Node.js official documentation to prevent file system
race conditions.

Changes:
- python-env-manager.ts: Use writeFileSync with { flag: 'wx' } and handle
  EEXIST error silently (file already exists is expected)
- download-python.cjs: Same pattern for __init__.py creation
- Updated tests to verify new atomic write behavior

The 'wx' flag atomically fails if the file exists (EEXIST), eliminating
the window between existsSync check and writeFileSync where another
process could create/modify the file.

Reference: https://nodejs.org/api/fs.html#file-system-flags

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Use taskkill /f /t on Windows to properly kill process trees
  (SIGTERM/SIGKILL are ignored on Windows)
- Make killAllProcesses() wait for process exit events with timeout
- Kill PTY daemon process on shutdown
- Clear periodic update check interval on app quit

Fixes process accumulation in Task Manager after closing Auto-Claude.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 17, 2026

📝 Walkthrough

Walkthrough

Introduces comprehensive Windows-specific improvements: bundled Python pywin32 DLL handling with file copying and startup script bootstrap logic, platform-aware process termination with Windows taskkill fallback and Unix signal sequencing, and periodic update check cleanup during app shutdown.

Changes

Cohort / File(s) Change Summary
Python Runtime Bundling & DLL Fixes
apps/frontend/scripts/download-python.cjs, apps/frontend/src/main/python-env-manager.ts
Adds comprehensive pywin32 module detection, DLL copying, and bootstrap script generation to download-python.cjs. Implements Windows-specific environment setup in python-env-manager.ts with PYTHONPATH augmentation for win32 paths, PATH adjustments for pywin32_system32, and automatic creation of startup script for DLL loading.
Process Lifecycle Management
apps/frontend/src/main/agent/agent-process.ts, apps/frontend/src/main/terminal/pty-daemon-client.ts
Reworks killProcess to handle Windows taskkill fallback (5s timeout) vs Unix SIGTERM/SIGKILL sequencing. Introduces killAllProcesses() method with 10s timeout for coordinated multi-process termination. Adds Windows-specific daemon shutdown via taskkill in PTY client.
App Lifecycle & Update Management
apps/frontend/src/main/app-updater.ts, apps/frontend/src/main/index.ts
Adds interval tracking and new stopPeriodicUpdates() API to cleanly halt periodic update checks. Wires cleanup into before-quit handler for graceful shutdown.
Test Coverage
apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts, apps/frontend/src/main/__tests__/python-env-manager.test.ts
Adds platform-aware process kill assertions (Windows vs Unix signal handling). Introduces comprehensive test suite for PythonEnvManager covering Windows pywin32 bootstrap, PATH/PYTHONPATH construction, and startup script generation with file system mocking.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • #1252: Directly addresses Windows process-tree killing, PTY-daemon termination, and app-updater interval cleanup requirements.

Possibly related PRs

  • #1197: Both modify Windows pywin32 bundling codepaths in download-python.cjs and python-env-manager.ts to ensure pywin32 is properly configured for packaged Python.
  • #284: Foundational bundled Python runtime packaging; main PR layers pywin32-specific fixes on top of this bundling work.
  • #777: Main PR enhances PythonEnvManager with Windows/pywin32 startup handling that directly affects the pythonEnv consumed by subprocess environment configuration.

Suggested labels

bug, area/frontend, os/windows, size/M, priority/medium, 🔄 Checking

Suggested reviewers

  • AndyMik90

Poem

🐇 A bundled Python now takes its flight,
With DLL paths aligned just right,
Windows taskkill and signals too,
Process trees fall on cue,
Startup scripts bootstrap the night!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: preventing zombie process accumulation on Windows during app close, which is the primary objective of the PR.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @VDT-91, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly improves the application's shutdown behavior on Windows by preventing the accumulation of orphaned processes. It ensures that all spawned child processes, including agent processes and the PTY daemon, are properly terminated when the application closes. Additionally, it resolves specific pywin32 library loading issues on Windows, enhancing the stability of Python-dependent features within the bundled application.

Highlights

  • Windows Process Termination: Implemented robust process termination on Windows using taskkill /f /t to ensure all child processes are killed, addressing issues where SIGTERM/SIGKILL signals are ignored.
  • Graceful Shutdown for Processes: The killAllProcesses() function now waits for processes to exit with a 10-second timeout, preventing immediate resolution and ensuring proper cleanup.
  • PTY Daemon Cleanup: The PTY daemon process is now explicitly killed during application shutdown, preventing it from becoming an orphaned process.
  • App Updater Interval Management: The periodic update check interval for the app updater is now stored and cleared during application quit, preventing background activity after the app closes.
  • Pywin32 Installation Fix: Addressed pywin32 installation and DLL loading issues for bundled Python packages on Windows by copying necessary files, creating an __init__.py for pywin32_system32, and generating a PYTHONSTARTUP bootstrap script to correctly configure environment variables and DLL search paths.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@sentry
Copy link

sentry bot commented Jan 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

// This avoids TOCTOU race condition where existsSync + writeFileSync could
// allow another process to create/modify the file between check and write.
// See: https://nodejs.org/api/fs.html#file-system-flags
writeFileSync(startupScript, scriptContent, { encoding: 'utf-8', flag: 'wx' });

Check failure

Code scanning / CodeQL

Insecure temporary file High

Insecure creation of file in
the os temp dir
.
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces several important fixes to prevent zombie processes on Windows when closing the application. The changes include platform-aware process killing logic in agent-process.ts and pty-daemon-client.ts, ensuring taskkill is used on Windows. The killAllProcesses function is now asynchronous and correctly waits for processes to exit, which is a key part of the fix. Additionally, the app updater's periodic check is now properly cleaned up on application quit.

A significant portion of the changes involves complex workarounds for pywin32 installation and DLL loading issues on Windows, both in the build script (download-python.cjs) and at runtime (python-env-manager.ts). While these fixes appear robust and are well-tested, I've identified a couple of areas where maintainability could be improved by reducing code duplication. My review includes suggestions to address these points.

Comment on lines +789 to +832
const scriptContent = `# Auto-Claude pywin32 bootstrap script
# This script runs via PYTHONSTARTUP before the main script.
# It ensures pywin32 DLLs can be found on Python 3.8+ where
# os.add_dll_directory() is required for DLL search paths.
#
# See: https://github.com/AndyMik90/Auto-Claude/issues/810
# See: https://github.com/mhammond/pywin32/blob/main/win32/Lib/pywin32_bootstrap.py
import os
import sys
def _bootstrap_pywin32():
"""Bootstrap pywin32 DLL loading for Python 3.8+"""
# Get the site-packages directory (where this script is located)
site_packages = os.path.dirname(os.path.abspath(__file__))
# 1. Add pywin32_system32 to DLL search path (Python 3.8+ requirement)
# This is the critical fix - without this, pywintypes DLL cannot be loaded
pywin32_system32 = os.path.join(site_packages, 'pywin32_system32')
if os.path.isdir(pywin32_system32):
if hasattr(os, 'add_dll_directory'):
try:
os.add_dll_directory(pywin32_system32)
except OSError:
pass # Directory already added or doesn't exist
# Also add to PATH as fallback for edge cases
current_path = os.environ.get('PATH', '')
if pywin32_system32 not in current_path:
os.environ['PATH'] = pywin32_system32 + os.pathsep + current_path
# 2. Use site.addsitedir() to process .pth files
# This triggers pywin32.pth which imports pywin32_bootstrap
# The bootstrap adds win32, win32/lib to sys.path and calls add_dll_directory
try:
import site
if site_packages not in sys.path:
site.addsitedir(site_packages)
except Exception:
pass # site module issues shouldn't break the app
# Run bootstrap immediately when this script is loaded
_bootstrap_pywin32()
`;
Copy link
Contributor

Choose a reason for hiding this comment

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

high

This Python bootstrap script content is duplicated from apps/frontend/scripts/download-python.cjs. The comment on line 779 even highlights that they must be kept in sync. This creates a significant maintainability risk, as changes in one place might be forgotten in the other, leading to hard-to-debug inconsistencies between the build-time and runtime environments.

To avoid this, I recommend moving the script content to a single, separate file (e.g., pywin32-bootstrap.py.template) and having both download-python.cjs and python-env-manager.ts read from that file. This would create a single source of truth for the script.

Comment on lines +699 to +723
const dllFiles = fs.readdirSync(pywin32System32).filter(f => f.endsWith('.dll'));
for (const dll of dllFiles) {
const srcPath = path.join(pywin32System32, dll);
const destPath = path.join(win32Dir, dll);

try {
fs.copyFileSync(srcPath, destPath);
console.log(`[download-python] Copied ${dll} to win32/`);
} catch (err) {
console.warn(`[download-python] Failed to copy ${dll} to win32/: ${err.message}`);
}
}

// 5. Also copy DLLs to site-packages root for maximum compatibility
for (const dll of dllFiles) {
const srcPath = path.join(pywin32System32, dll);
const destPath = path.join(sitePackagesDir, dll);

try {
fs.copyFileSync(srcPath, destPath);
console.log(`[download-python] Copied ${dll} to site-packages root`);
} catch (err) {
console.warn(`[download-python] Failed to copy ${dll}: ${err.message}`);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

These two loops for copying DLLs to different destinations contain duplicated logic. To improve maintainability and reduce redundancy, you can refactor this into a single loop that iterates over a list of target destinations.

const dllFiles = fs.readdirSync(pywin32System32).filter(f => f.endsWith('.dll'));
const copyTargets = [
  { dir: win32Dir, name: 'win32/' },
  { dir: sitePackagesDir, name: 'site-packages root' },
];

for (const dll of dllFiles) {
  const srcPath = path.join(pywin32System32, dll);
  for (const target of copyTargets) {
    const destPath = path.join(target.dir, dll);
    try {
      fs.copyFileSync(srcPath, destPath);
      console.log(`[download-python] Copied ${dll} to ${target.name}`);
    } catch (err) {
      console.warn(`[download-python] Failed to copy ${dll} to ${target.name}: ${err.message}`);
    }
  }
}

@VDT-91
Copy link
Contributor Author

VDT-91 commented Jan 17, 2026

Closing in favor of #1259 which contains only the Windows process cleanup fix (without unrelated pywin32 commits that were accidentally included).

@VDT-91 VDT-91 closed this Jan 17, 2026
@VDT-91 VDT-91 deleted the fix/windows-process-cleanup branch January 17, 2026 16:27
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: 6

🤖 Fix all issues with AI agents
In `@apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts`:
- Around line 296-301: Replace direct reads of process.platform in the test with
parameterized cases that mock platform detection via the platform abstraction
module (the same pattern as in platform.test.ts); for the test around
mockProcess.kill in subprocess-spawn tests, iterate the platforms
['win32','darwin','linux'], stub the platform detection to return each value,
run the shutdown logic that calls mockProcess.kill, and assert for 'win32' that
mockProcess.kill was called with no args and for 'darwin' and 'linux' that
mockProcess.kill was called with 'SIGTERM' (use the existing mockProcess.kill
reference and the subprocess spawn/shutdown function under test to locate where
to run the assertions).

In `@apps/frontend/src/main/__tests__/python-env-manager.test.ts`:
- Around line 186-201: Update the test that checks non-Windows behavior to run
for both 'darwin' and 'linux' platforms: iterate or parameterize over the
platforms array (e.g., ['darwin','linux']), set process.platform to each value
before calling manager.getPythonEnv(), and assert that (manager as
any).sitePackagesPath is used as PYTHONPATH and PYTHONSTARTUP is undefined;
reference the existing test’s use of process.platform, (manager as
any).sitePackagesPath, and manager.getPythonEnv to locate and modify the test.
Ensure you restore any mocked platform state between iterations.
- Around line 107-109: Replace the repeated "(manager as any)" casts by
introducing a typed test helper reference for the manager (e.g., a local const
testManager typed to the test helper / mock manager interface) and use that
helper to set sitePackagesPath and other properties instead of "as any"; update
each occurrence referenced (around the areas noted) to use the typed helper.
Also add a Linux platform unit test alongside the existing darwin test so
non-Windows coverage includes both macOS and Linux (i.e., duplicate the darwin
platform test case for linux and ensure platform-specific branches exercise both
darwin and linux paths).

In `@apps/frontend/src/main/agent/agent-process.ts`:
- Around line 700-732: The Windows fallback can run after the child already
exited and its PID reused; modify the isWindows() branch around
agentProcess.process.kill()/spawn(...) to store the setTimeout handle (e.g.,
const taskkillTimeout = setTimeout(...)), attach an 'exit' listener on
agentProcess.process that clears that timeout, and inside the timeout callback
check that the process has not already exited by verifying the exitCode is null
(agentProcess.process.exitCode === null) before calling spawn('taskkill', ...);
also ensure you remove the 'exit' listener after it fires to avoid leaks and
keep existing try/catch behavior.

In `@apps/frontend/src/main/app-updater.ts`:
- Around line 41-43: The periodic interval variable periodicCheckIntervalId may
be re-used if initializeAppUpdater runs multiple times; before creating a new
setInterval in initializeAppUpdater, check if periodicCheckIntervalId is
non-null and call clearInterval(periodicCheckIntervalId) and set it to null,
then create and assign the new interval; also ensure any shutdown/cleanup
function (where periodicCheckIntervalId is used, e.g., app shutdown logic)
similarly clears and nulls periodicCheckIntervalId to avoid duplicate timers.

In `@apps/frontend/src/main/python-env-manager.ts`:
- Around line 704-723: The code currently uses direct platform checks and
hardcoded delimiters when building pythonPath and configuring windowsEnv
(references: this.sitePackagesPath, pythonPath, windowsEnv, pywin32System32);
replace process.platform === 'win32' and the hardcoded ';' with the platform
helpers isWindows() and getPathDelimiter() respectively in both Windows-specific
blocks so the logic uses isWindows() to gate the Windows-only branches and
getPathDelimiter() when joining paths (ensure you update both the PYTHONPATH
construction and pywin32_system32 handling to use these helpers).

Comment on lines +296 to +301
// On Windows, kill() is called without arguments; on Unix, kill('SIGTERM') is used
if (process.platform === 'win32') {
expect(mockProcess.kill).toHaveBeenCalled();
} else {
expect(mockProcess.kill).toHaveBeenCalledWith('SIGTERM');
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find platform-related utility files
fd -t f -i platform . --extension ts --extension tsx --extension js | head -20

Repository: AndyMik90/Auto-Claude

Length of output: 164


🏁 Script executed:

# Check the test file to understand its structure and imports
head -50 apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1804


🏁 Script executed:

# Search for platform detection functions in the codebase
rg -t ts -t tsx "isWindows|isMacOS|isLinux" --max-count 10

Repository: AndyMik90/Auto-Claude

Length of output: 92


🏁 Script executed:

# Check if process.platform is used elsewhere in tests
rg -t ts "process\.platform" apps/frontend/src/__tests__/ -B 2 -A 2

Repository: AndyMik90/Auto-Claude

Length of output: 622


🏁 Script executed:

# Check the platform abstraction module
cat -n apps/frontend/src/shared/platform.ts

Repository: AndyMik90/Auto-Claude

Length of output: 2080


🏁 Script executed:

# Check the platform tests to see how they handle multi-platform testing
cat -n apps/frontend/src/main/platform/__tests__/platform.test.ts | head -100

Repository: AndyMik90/Auto-Claude

Length of output: 3234


🏁 Script executed:

# Look at the full test file context around the problematic code
sed -n '280,310p' apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1170


🏁 Script executed:

# Check imports in the test file
grep -n "^import\|^from" apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 363


Parameterize and mock platform detection to test all three platforms.

This test uses process.platform directly instead of importing platform detection functions from the platform abstraction module. More importantly, it only validates the behavior for the test runner's OS. Per coding guidelines and the established pattern in apps/frontend/src/main/platform/__tests__/platform.test.ts, use parameterized tests or separate test cases that mock process.platform to verify all three behaviors (Windows, macOS, Linux) regardless of the runner's platform.

🤖 Prompt for AI Agents
In `@apps/frontend/src/__tests__/integration/subprocess-spawn.test.ts` around
lines 296 - 301, Replace direct reads of process.platform in the test with
parameterized cases that mock platform detection via the platform abstraction
module (the same pattern as in platform.test.ts); for the test around
mockProcess.kill in subprocess-spawn tests, iterate the platforms
['win32','darwin','linux'], stub the platform detection to return each value,
run the shutdown logic that calls mockProcess.kill, and assert for 'win32' that
mockProcess.kill was called with no args and for 'darwin' and 'linux' that
mockProcess.kill was called with 'SIGTERM' (use the existing mockProcess.kill
reference and the subprocess spawn/shutdown function under test to locate where
to run the assertions).

Comment on lines +107 to +109
(manager as any).sitePackagesPath = sitePackagesPath;

// Mock existsSync to return true for the startup script
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, verify the file exists and check its line count
wc -l apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 128


🏁 Script executed:

# Read the relevant sections of the test file to verify the any-casts
sed -n '100,115p' apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 697


🏁 Script executed:

# Check the additional line ranges mentioned
sed -n '120,125p' apps/frontend/src/main/__tests__/python-env-manager.test.ts
sed -n '137,145p' apps/frontend/src/main/__tests__/python-env-manager.test.ts
sed -n '156,165p' apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1017


🏁 Script executed:

# Look for non-Windows test patterns to verify darwin-only concern
rg -A 5 -B 5 "describe.*non.?Windows|describe.*darwin" apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 47


🏁 Script executed:

# Check if there's a platform abstraction module referenced in guidelines
fd -t f "platform" apps/frontend/src/main/ --type f | head -20

Repository: AndyMik90/Auto-Claude

Length of output: 123


🏁 Script executed:

# Search for platform module imports in the test file
rg "import.*platform" apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 47


🏁 Script executed:

# Read the test file structure to understand describe blocks and test organization
head -60 apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1673


🏁 Script executed:

# Look for all describe and it blocks to understand test structure
rg "^\s*(describe|it)\(" apps/frontend/src/main/__tests__/python-env-manager.test.ts | head -30

Repository: AndyMik90/Auto-Claude

Length of output: 1137


🏁 Script executed:

# Search for platform-related mocking in the entire test file
rg "process.platform|mockReturnValue|darwin|linux|win32" apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 2456


🏁 Script executed:

# Check the platform abstraction module to understand available functions
cat apps/frontend/src/main/platform/*.ts | head -80

Repository: AndyMik90/Auto-Claude

Length of output: 2024


🏁 Script executed:

# Look for how other tests in the codebase handle cross-platform testing
rg -B 2 -A 5 "darwin.*linux|linux.*win32" apps/frontend/src/main/__tests__/ | head -40

Repository: AndyMik90/Auto-Claude

Length of output: 47


🏁 Script executed:

# Search specifically for linux platform testing
rg "linux" apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 47


🏁 Script executed:

# Get the non-Windows platform test in detail
sed -n '170,185p' apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 580


🏁 Script executed:

# Check how many non-Windows tests exist and what platforms they test
rg -B 3 "Object.defineProperty.*platform" apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1149


🏁 Script executed:

# Check if the test file imports from the platform abstraction module
head -30 apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 850


🏁 Script executed:

# Get exact line numbers for all any-casts in the test file
rg -n "as any" apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 617


🏁 Script executed:

# Verify the specific line ranges mentioned: 107-109, 123-124, 140-141, 159-160, 193-194, 221-223, 246-248, 291-292
for range in "107,109" "123,124" "140,141" "159,160" "193,194" "221,223" "246,248" "291,292"; do
  echo "=== Lines $range ==="
  sed -n "${range}p" apps/frontend/src/main/__tests__/python-env-manager.test.ts
done

Repository: AndyMik90/Auto-Claude

Length of output: 880


🏁 Script executed:

# Check the full non-Windows platform test section to see if linux should be tested
sed -n '165,175p' apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 546


🏁 Script executed:

# Verify how the platform module should be used in tests
grep -r "isWindows\|isMacOS\|isLinux" apps/frontend/src/main/__tests__/ | head -10

Repository: AndyMik90/Auto-Claude

Length of output: 47


🏁 Script executed:

# Check if there are examples of platform abstraction usage in other test files
rg "from.*platform" apps/frontend/src/main/__tests__/ -A 2

Repository: AndyMik90/Auto-Claude

Length of output: 47


🏁 Script executed:

# Verify the exact structure of the non-Windows test to confirm it only tests darwin
sed -n '165,180p' apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 718


🏁 Script executed:

# Check if PythonEnvManager uses platform abstraction functions internally
grep -n "isWindows\|isMacOS\|isLinux\|process.platform" apps/frontend/src/main/python-env-manager.ts

Repository: AndyMik90/Auto-Claude

Length of output: 452


🏁 Script executed:

# Get a broader view of the non-Windows platform test block
sed -n '161,175p' apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 746


🏁 Script executed:

# Check if there's guidance on how to mock platform functions for testing
cat apps/frontend/src/main/platform/types.ts 2>/dev/null | head -20

Repository: AndyMik90/Auto-Claude

Length of output: 425


🏁 Script executed:

# Find the exact non-Windows platform test block
sed -n '155,180p' apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1153


🏁 Script executed:

# Check what the test validates to understand if linux coverage is needed
sed -n '163,176p' apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 702


🏁 Script executed:

# Look at the implementation to see if behavior differs between darwin and linux
sed -n '700,730p' apps/frontend/src/main/python-env-manager.ts

Repository: AndyMik90/Auto-Claude

Length of output: 1736


🏁 Script executed:

# Find the complete "should not add Windows-specific env vars on non-Windows platforms" test
rg -B 5 -A 15 "should not add Windows-specific env vars on non-Windows platforms" apps/frontend/src/main/__tests__/python-env-manager.test.ts

Repository: AndyMik90/Auto-Claude

Length of output: 801


🏁 Script executed:

# Check if there are separate test cases for linux and darwin, or just one non-Windows test
rg -n "it\(" apps/frontend/src/main/__tests__/python-env-manager.test.ts | grep -i "windows\|darwin\|linux\|platform"

Repository: AndyMik90/Auto-Claude

Length of output: 488


Replace as any casts with a typed test helper and add linux platform test coverage.

ESLint flags Unexpected any; a typed helper avoids repeated casts and keeps intent clear. The non-Windows platform test currently covers only darwin; per coding guidelines, platform-specific tests must cover all three platforms (Windows, macOS, Linux).

🧩 Example refactor
+type TestablePythonEnvManager = PythonEnvManager & {
+  sitePackagesPath: string | null;
+  ensurePywin32StartupScript(sitePackagesPath: string): void;
+};
+
-  let manager: PythonEnvManager;
+  let manager: TestablePythonEnvManager;
   beforeEach(() => {
-    manager = new PythonEnvManager();
+    manager = new PythonEnvManager() as TestablePythonEnvManager;
     vi.clearAllMocks();
   });
@@
-      (manager as any).sitePackagesPath = sitePackagesPath;
+      manager.sitePackagesPath = sitePackagesPath;
@@
-      const ensureScript = (manager as any).ensurePywin32StartupScript.bind(manager);
+      const ensureScript = manager.ensurePywin32StartupScript.bind(manager);

Add linux test alongside the darwin test to cover all non-Windows platforms.

Also applies to: 123-124, 140-141, 159-160, 193-194, 221-223, 246-248, 291-292

🧰 Tools
🪛 GitHub Check: TypeScript (ESLint)

[warning] 107-107:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
In `@apps/frontend/src/main/__tests__/python-env-manager.test.ts` around lines 107
- 109, Replace the repeated "(manager as any)" casts by introducing a typed test
helper reference for the manager (e.g., a local const testManager typed to the
test helper / mock manager interface) and use that helper to set
sitePackagesPath and other properties instead of "as any"; update each
occurrence referenced (around the areas noted) to use the typed helper. Also add
a Linux platform unit test alongside the existing darwin test so non-Windows
coverage includes both macOS and Linux (i.e., duplicate the darwin platform test
case for linux and ensure platform-specific branches exercise both darwin and
linux paths).

Comment on lines +186 to +201
it('should not add Windows-specific env vars on non-Windows platforms', () => {
// Restore non-Windows platform
Object.defineProperty(process, 'platform', { value: 'darwin' });

const sitePackagesPath = '/test/site-packages';

// Access private property for testing
(manager as any).sitePackagesPath = sitePackagesPath;

const env = manager.getPythonEnv();

// Should not have PYTHONSTARTUP set
expect(env.PYTHONSTARTUP).toBeUndefined();

// PYTHONPATH should just be the site-packages (no win32 additions)
expect(env.PYTHONPATH).toBe(sitePackagesPath);
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check if the test file exists and examine the specific section
wc -l "apps/frontend/src/main/__tests__/python-env-manager.test.ts"

Repository: AndyMik90/Auto-Claude

Length of output: 186


🏁 Script executed:

# Read the test file around the lines mentioned (186-201) with context
sed -n '170,220p' "apps/frontend/src/main/__tests__/python-env-manager.test.ts"

Repository: AndyMik90/Auto-Claude

Length of output: 1730


🏁 Script executed:

# Search for other platform-related tests in the file to understand full test coverage
rg -n "should not add Windows|darwin|linux|win32" "apps/frontend/src/main/__tests__/python-env-manager.test.ts"

Repository: AndyMik90/Auto-Claude

Length of output: 1826


Test non-Windows behavior on both macOS and Linux.

The test only covers the darwin platform; add linux to the parameterization to match the guideline requirement of testing all three platforms (Windows, macOS, Linux).

Example parameterization
-    it('should not add Windows-specific env vars on non-Windows platforms', () => {
-      Object.defineProperty(process, 'platform', { value: 'darwin' });
+    it.each(['darwin', 'linux'])(
+      'should not add Windows-specific env vars on %s',
+      (platform) => {
+        Object.defineProperty(process, 'platform', { value: platform });
@@
-    });
+      }
+    );
🧰 Tools
🪛 GitHub Check: TypeScript (ESLint)

[warning] 193-193:
Unexpected any. Specify a different type

🤖 Prompt for AI Agents
In `@apps/frontend/src/main/__tests__/python-env-manager.test.ts` around lines 186
- 201, Update the test that checks non-Windows behavior to run for both 'darwin'
and 'linux' platforms: iterate or parameterize over the platforms array (e.g.,
['darwin','linux']), set process.platform to each value before calling
manager.getPythonEnv(), and assert that (manager as any).sitePackagesPath is
used as PYTHONPATH and PYTHONSTARTUP is undefined; reference the existing test’s
use of process.platform, (manager as any).sitePackagesPath, and
manager.getPythonEnv to locate and modify the test. Ensure you restore any
mocked platform state between iterations.

Comment on lines +700 to +732
if (isWindows()) {
// Windows: .kill() then taskkill fallback
// SIGTERM/SIGKILL are ignored on Windows, so we use taskkill /f /t
try {
agentProcess.process.kill();
if (agentProcess.process.pid) {
const pid = agentProcess.process.pid;
setTimeout(() => {
try {
// taskkill /f = force kill, /t = kill child processes tree
spawn('taskkill', ['/pid', pid.toString(), '/f', '/t'], {
stdio: 'ignore',
detached: true
}).unref();
} catch {
// Process may already be dead
}
}, 5000);
}
} catch {
// Process may already be dead
}
}, 5000);
} else {
// Unix: SIGTERM then SIGKILL
agentProcess.process.kill('SIGTERM');
setTimeout(() => {
try {
agentProcess.process.kill('SIGKILL');
} catch {
// Process may already be dead
}
}, 5000);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's locate and read the relevant file
find apps/frontend -name "agent-process.ts" -type f | head -5

Repository: AndyMik90/Auto-Claude

Length of output: 186


🏁 Script executed:

# Read the full context around lines 700-732
cat -n apps/frontend/src/main/agent/agent-process.ts | sed -n '680,780p'

Repository: AndyMik90/Auto-Claude

Length of output: 3677


🏁 Script executed:

# Check for isWindows import and platform module usage
grep -n "isWindows\|isMacOS\|isLinux\|platform" apps/frontend/src/main/agent/agent-process.ts | head -20

Repository: AndyMik90/Auto-Claude

Length of output: 266


🏁 Script executed:

# Search for existing exit event handlers and process lifecycle handling
grep -n "\.once\|\.on\|exit\|exitCode" apps/frontend/src/main/agent/agent-process.ts | head -20

Repository: AndyMik90/Auto-Claude

Length of output: 922


🏁 Script executed:

# Check the broader killProcess and killAllProcesses context
cat -n apps/frontend/src/main/agent/agent-process.ts | sed -n '690,800p'

Repository: AndyMik90/Auto-Claude

Length of output: 4558


🌐 Web query:

Node.js ChildProcess exitCode property null timing when process exits

💡 Result:

Short answer: child.exitCode is null while the child is still running and is only set once the child has actually exited. Check it (or use the exit/close event callbacks) after the 'exit' or 'close' events — 'exit' gives the numeric code/signal when the process ends, and 'close' is emitted after stdio streams are closed (and always after 'exit'). [1][2]

References:

  • Node.js ChildProcess docs (exitCode / exit / close). [1] [2]

🌐 Web query:

Windows PID reuse timeout how quickly can PID be reused

💡 Result:

Short answer: Windows has no fixed "timeout" — a PID can be reused as soon as the terminated process's kernel process object is destroyed (i.e., the process has exited and the last handles/references to its object are closed), so reuse can be effectively immediate under load. Use an open process handle or compare creation times to detect/reject reuse. [1][2][3]

Sources:

  • Microsoft Learn: GetProcessId / GetProcessIdOfThread (remarks about PID uniqueness only while process exists). [1]
  • OSR/NTDEV discussion on PID reuse and delaying reuse by holding a handle/object reference. [2]
  • Practical guidance (ToolHelp/Handle, check creation time) about PID reuse when building process trees. [3]

Guard Windows taskkill against stale PID reuse.

The 5s fallback taskkill can fire after the process exits; Windows reuses PIDs immediately, risking termination of an unrelated process. Listen to the exit event to clear the timeout and check exitCode === null before executing taskkill to prevent stale invocations.

🛠️ Suggested fix
-        if (isWindows()) {
-          // Windows: .kill() then taskkill fallback
-          // SIGTERM/SIGKILL are ignored on Windows, so we use taskkill /f /t
-          try {
-            agentProcess.process.kill();
-            if (agentProcess.process.pid) {
-              const pid = agentProcess.process.pid;
-              setTimeout(() => {
-                try {
-                  // taskkill /f = force kill, /t = kill child processes tree
-                  spawn('taskkill', ['/pid', pid.toString(), '/f', '/t'], {
-                    stdio: 'ignore',
-                    detached: true
-                  }).unref();
-                } catch {
-                  // Process may already be dead
-                }
-              }, 5000);
-            }
-          } catch {
-            // Process may already be dead
-          }
-        } else {
+        if (isWindows()) {
+          // Windows: .kill() then taskkill fallback (cancel if the process exits)
+          const pid = agentProcess.process.pid;
+          let fallbackTimer: NodeJS.Timeout | undefined;
+          const clearFallback = () => {
+            if (fallbackTimer) clearTimeout(fallbackTimer);
+          };
+          if (typeof agentProcess.process.once === 'function') {
+            agentProcess.process.once('exit', clearFallback);
+          }
+          try {
+            agentProcess.process.kill();
+          } catch {
+            // Process may already be dead
+          }
+          if (pid) {
+            fallbackTimer = setTimeout(() => {
+              if (agentProcess.process.exitCode === null) {
+                try {
+                  // taskkill /f = force kill, /t = kill child processes tree
+                  spawn('taskkill', ['/pid', pid.toString(), '/f', '/t'], {
+                    stdio: 'ignore',
+                    detached: true
+                  }).unref();
+                } catch {
+                  // Process may already be dead
+                }
+              }
+            }, 5000);
+          }
+        } else {
🤖 Prompt for AI Agents
In `@apps/frontend/src/main/agent/agent-process.ts` around lines 700 - 732, The
Windows fallback can run after the child already exited and its PID reused;
modify the isWindows() branch around agentProcess.process.kill()/spawn(...) to
store the setTimeout handle (e.g., const taskkillTimeout = setTimeout(...)),
attach an 'exit' listener on agentProcess.process that clears that timeout, and
inside the timeout callback check that the process has not already exited by
verifying the exitCode is null (agentProcess.process.exitCode === null) before
calling spawn('taskkill', ...); also ensure you remove the 'exit' listener after
it fires to avoid leaks and keep existing try/catch behavior.

Comment on lines +41 to +43
// Store interval ID for cleanup during shutdown
let periodicCheckIntervalId: ReturnType<typeof setInterval> | null = 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

Guard against duplicate periodic intervals.

If initializeAppUpdater can run more than once (e.g., re-init after window recreation), a previous interval can keep running. Consider clearing any existing interval before creating a new one.

♻️ Proposed fix
-  periodicCheckIntervalId = setInterval(() => {
+  if (periodicCheckIntervalId) {
+    clearInterval(periodicCheckIntervalId);
+    periodicCheckIntervalId = null;
+  }
+  periodicCheckIntervalId = setInterval(() => {
     console.warn('[app-updater] Performing periodic update check');
     autoUpdater.checkForUpdates().catch((error) => {
       console.error('[app-updater] ❌ Periodic update check failed:', error.message);
       if (DEBUG_UPDATER) {
         console.error('[app-updater:debug] Full error:', error);
       }
     });
   }, FOUR_HOURS);

Also applies to: 195-195

🤖 Prompt for AI Agents
In `@apps/frontend/src/main/app-updater.ts` around lines 41 - 43, The periodic
interval variable periodicCheckIntervalId may be re-used if initializeAppUpdater
runs multiple times; before creating a new setInterval in initializeAppUpdater,
check if periodicCheckIntervalId is non-null and call
clearInterval(periodicCheckIntervalId) and set it to null, then create and
assign the new interval; also ensure any shutdown/cleanup function (where
periodicCheckIntervalId is used, e.g., app shutdown logic) similarly clears and
nulls periodicCheckIntervalId to avoid duplicate timers.

Comment on lines +704 to +723
// Build PYTHONPATH - for Windows with pywin32, we need to include win32 and win32/lib
// since the .pth file that normally adds these isn't processed when using PYTHONPATH
let pythonPath = this.sitePackagesPath || '';
if (this.sitePackagesPath && process.platform === 'win32') {
const pathSep = ';'; // Windows path separator
const win32Path = path.join(this.sitePackagesPath, 'win32');
const win32LibPath = path.join(this.sitePackagesPath, 'win32', 'lib');
pythonPath = [this.sitePackagesPath, win32Path, win32LibPath].join(pathSep);
}

// Windows-specific pywin32 DLL loading fix
// On Windows with bundled packages, we need to ensure pywin32 DLLs can be found.
// Python 3.8+ requires os.add_dll_directory() for DLL search paths.
// We achieve this by:
// 1. Adding pywin32_system32 to PATH (fallback for some edge cases)
// 2. Setting PYTHONSTARTUP to bootstrap script that calls os.add_dll_directory()
// and uses site.addsitedir() to process .pth files (which imports pywin32_bootstrap)
let windowsEnv: Record<string, string> = {};
if (this.sitePackagesPath && process.platform === 'win32') {
const pywin32System32 = path.join(this.sitePackagesPath, 'pywin32_system32');
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find the file mentioned in the review
find . -name "python-env-manager.ts" -type f

Repository: AndyMik90/Auto-Claude

Length of output: 111


🏁 Script executed:

# List platform-related files to find the platform abstraction module
find . -path "*/main/platform*" -o -path "*/src/platform*" | head -20

Repository: AndyMik90/Auto-Claude

Length of output: 332


🏁 Script executed:

# Look for platform module exports
fd -e ts -e js | xargs grep -l "export.*isWindows\|export.*getPathDelimiter" | head -5

Repository: AndyMik90/Auto-Claude

Length of output: 142


🏁 Script executed:

# Check the platform module exports
cat apps/frontend/src/main/platform/index.ts

Repository: AndyMik90/Auto-Claude

Length of output: 10296


🏁 Script executed:

# Check python-env-manager.ts at the specified lines and around
sed -n '700,760p' apps/frontend/src/main/python-env-manager.ts | cat -n

Repository: AndyMik90/Auto-Claude

Length of output: 3500


🏁 Script executed:

# Check current imports in python-env-manager.ts
head -50 apps/frontend/src/main/python-env-manager.ts | cat -n

Repository: AndyMik90/Auto-Claude

Length of output: 2319


🏁 Script executed:

# Check lines 721-760 to see the full scope of "Also applies to: 721-753"
sed -n '721,760p' apps/frontend/src/main/python-env-manager.ts | cat -n

Repository: AndyMik90/Auto-Claude

Length of output: 2238


Replace direct process.platform checks and hardcoded delimiters with platform abstraction helpers.

The code uses process.platform === 'win32' checks and hardcoded ; path separators directly instead of the platform abstraction module. Replace these with isWindows() and getPathDelimiter() throughout both Windows-specific blocks (lines 704–723 and 721–754).

♻️ Suggested patch
-import { isLinux, isWindows } from './platform';
+import { isLinux, isWindows, getPathDelimiter } from './platform';
@@
-    if (this.sitePackagesPath && process.platform === 'win32') {
-      const pathSep = ';';  // Windows path separator
+    if (this.sitePackagesPath && isWindows()) {
+      const pathSep = getPathDelimiter();
       const win32Path = path.join(this.sitePackagesPath, 'win32');
       const win32LibPath = path.join(this.sitePackagesPath, 'win32', 'lib');
       pythonPath = [this.sitePackagesPath, win32Path, win32LibPath].join(pathSep);
     }

     let windowsEnv: Record<string, string> = {};
-    if (this.sitePackagesPath && process.platform === 'win32') {
+    if (this.sitePackagesPath && isWindows()) {
       const pywin32System32 = path.join(this.sitePackagesPath, 'pywin32_system32');

       const currentPath = baseEnv['PATH'] || baseEnv['Path'] || '';
       if (currentPath && !currentPath.includes(pywin32System32)) {
-        windowsEnv['PATH'] = `${pywin32System32};${currentPath}`;
+        windowsEnv['PATH'] = `${pywin32System32}${getPathDelimiter()}${currentPath}`;
       } else if (!currentPath) {
         windowsEnv['PATH'] = pywin32System32;
       }
🤖 Prompt for AI Agents
In `@apps/frontend/src/main/python-env-manager.ts` around lines 704 - 723, The
code currently uses direct platform checks and hardcoded delimiters when
building pythonPath and configuring windowsEnv (references:
this.sitePackagesPath, pythonPath, windowsEnv, pywin32System32); replace
process.platform === 'win32' and the hardcoded ';' with the platform helpers
isWindows() and getPathDelimiter() respectively in both Windows-specific blocks
so the logic uses isWindows() to gate the Windows-only branches and
getPathDelimiter() when joining paths (ensure you update both the PYTHONPATH
construction and pywin32_system32 handling to use these helpers).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant