fix(frontend): resolve PATH and PYTHONPATH issues in insights and changelog services (#558) (#610)

* fix(frontend): use getAugmentedEnv in insights and changelog services

Fixed 'Process exited with code null/1' errors in Insights panel by using
getAugmentedEnv() instead of raw process.env. When Electron launches from
Finder/Dock on macOS, process.env.PATH is minimal and doesn't include
tools like 'claude' CLI.

Changed files:
- insights/config.ts: Use getAugmentedEnv() in getProcessEnv()
- changelog/generator.ts: Use getAugmentedEnv() instead of manual PATH additions
- changelog/version-suggester.ts: Use getAugmentedEnv() instead of manual PATH additions

This reuses existing infrastructure (getAugmentedEnv) that's already used
throughout the frontend for GitHub/GitLab operations, ensuring consistency.

Fixes #558

Signed-off-by: Hunter Luisi <hluisi@gmail.com>

* chore: pin electron version for monorepo builds

electron-builder cannot compute version from hoisted node_modules
in npm workspaces when using caret versions (^39.2.7).

This is a known electron-builder issue. Pinning to exact version
(39.2.7) allows electron-builder to proceed without looking for
electron in local node_modules.

Signed-off-by: Hunter Luisi <hluisi@gmail.com>

* fix(frontend): show only stderr in error messages for cleaner output

Separate stderr tracking from combined output. Error messages now show
only actual errors (stderr) instead of mixed stdout+stderr, making
debugging clearer. Combined output still used for rate limit detection.

---------

Signed-off-by: Hunter Luisi <hluisi@gmail.com>
Co-authored-by: Andy <119136210+AndyMik90@users.noreply.github.com>
This commit is contained in:
Hunter Luisi
2026-01-03 05:23:11 -08:00
committed by GitHub
parent 14b3db56fa
commit f5be794346
5 changed files with 29 additions and 40 deletions
+1 -1
View File
@@ -114,7 +114,7 @@
"@vitejs/plugin-react": "^5.1.2",
"autoprefixer": "^10.4.22",
"cross-env": "^10.1.0",
"electron": "^39.2.7",
"electron": "39.2.7",
"electron-builder": "^26.0.12",
"electron-vite": "^5.0.0",
"eslint": "^9.39.1",
+5 -18
View File
@@ -13,6 +13,7 @@ import { extractChangelog } from './parser';
import { getCommits, getBranchDiffCommits } from './git-integration';
import { detectRateLimit, createSDKRateLimitInfo, getProfileEnv } from '../rate-limit-detector';
import { parsePythonCommand } from '../python-detector';
import { getAugmentedEnv } from '../env-utils';
/**
* Core changelog generation logic
@@ -246,21 +247,9 @@ export class ChangelogGenerator extends EventEmitter {
const homeDir = os.homedir();
const isWindows = process.platform === 'win32';
// Build PATH with platform-appropriate separator and locations
const pathAdditions = isWindows
? [
path.join(homeDir, 'AppData', 'Local', 'Programs', 'claude'),
path.join(homeDir, 'AppData', 'Roaming', 'npm'),
path.join(homeDir, '.local', 'bin'),
'C:\\Program Files\\Claude',
'C:\\Program Files (x86)\\Claude'
]
: [
'/usr/local/bin',
'/opt/homebrew/bin',
path.join(homeDir, '.local', 'bin'),
path.join(homeDir, 'bin')
];
// Use getAugmentedEnv() to ensure common tool paths are available
// even when app is launched from Finder/Dock
const augmentedEnv = getAugmentedEnv();
// Get active Claude profile environment (OAuth token preferred, falls back to CLAUDE_CONFIG_DIR)
const profileEnv = getProfileEnv();
@@ -271,15 +260,13 @@ export class ChangelogGenerator extends EventEmitter {
});
const spawnEnv: Record<string, string> = {
...process.env as Record<string, string>,
...augmentedEnv,
...this.autoBuildEnv,
...profileEnv, // Include active Claude profile config
// Ensure critical env vars are set for claude CLI
// Use USERPROFILE on Windows, HOME on Unix
...(isWindows ? { USERPROFILE: homeDir } : { HOME: homeDir }),
USER: process.env.USER || process.env.USERNAME || 'user',
// Add common binary locations to PATH for claude CLI
PATH: [process.env.PATH || '', ...pathAdditions].filter(Boolean).join(path.delimiter),
PYTHONUNBUFFERED: '1',
PYTHONIOENCODING: 'utf-8',
PYTHONUTF8: '1'
@@ -4,6 +4,7 @@ import * as os from 'os';
import type { GitCommit } from '../../shared/types';
import { getProfileEnv } from '../rate-limit-detector';
import { parsePythonCommand } from '../python-detector';
import { getAugmentedEnv } from '../env-utils';
interface VersionSuggestion {
version: string;
@@ -215,31 +216,19 @@ except Exception as e:
const homeDir = os.homedir();
const isWindows = process.platform === 'win32';
// Build PATH with platform-appropriate separator and locations
const pathAdditions = isWindows
? [
path.join(homeDir, 'AppData', 'Local', 'Programs', 'claude'),
path.join(homeDir, 'AppData', 'Roaming', 'npm'),
path.join(homeDir, '.local', 'bin'),
'C:\\Program Files\\Claude',
'C:\\Program Files (x86)\\Claude'
]
: [
'/usr/local/bin',
'/opt/homebrew/bin',
path.join(homeDir, '.local', 'bin'),
path.join(homeDir, 'bin')
];
// Use getAugmentedEnv() to ensure common tool paths are available
// even when app is launched from Finder/Dock
const augmentedEnv = getAugmentedEnv();
// Get active Claude profile environment
const profileEnv = getProfileEnv();
const spawnEnv: Record<string, string> = {
...process.env as Record<string, string>,
...augmentedEnv,
...profileEnv,
// Ensure critical env vars are set for claude CLI
...(isWindows ? { USERPROFILE: homeDir } : { HOME: homeDir }),
USER: process.env.USER || process.env.USERNAME || 'user',
PATH: [process.env.PATH || '', ...pathAdditions].filter(Boolean).join(path.delimiter),
PYTHONUNBUFFERED: '1',
PYTHONIOENCODING: 'utf-8',
PYTHONUTF8: '1'
+9 -2
View File
@@ -3,7 +3,8 @@ import { existsSync, readFileSync } from 'fs';
import { app } from 'electron';
import { getProfileEnv } from '../rate-limit-detector';
import { getValidatedPythonPath } from '../python-detector';
import { getConfiguredPythonPath } from '../python-env-manager';
import { getConfiguredPythonPath, pythonEnvManager } from '../python-env-manager';
import { getAugmentedEnv } from '../env-utils';
/**
* Configuration manager for insights service
@@ -107,9 +108,15 @@ export class InsightsConfig {
getProcessEnv(): Record<string, string> {
const autoBuildEnv = this.loadAutoBuildEnv();
const profileEnv = getProfileEnv();
// Get Python environment (PYTHONPATH for bundled packages like python-dotenv)
const pythonEnv = pythonEnvManager.getPythonEnv();
// Use getAugmentedEnv() to ensure common tool paths (claude, dotnet, etc.)
// are available even when app is launched from Finder/Dock
const augmentedEnv = getAugmentedEnv();
return {
...process.env as Record<string, string>,
...augmentedEnv,
...pythonEnv, // Include PYTHONPATH for bundled site-packages
...autoBuildEnv,
...profileEnv,
PYTHONUNBUFFERED: '1',
@@ -130,6 +130,7 @@ export class InsightsExecutor extends EventEmitter {
let suggestedTask: InsightsChatMessage['suggestedTask'] | undefined;
const toolsUsed: InsightsToolUsage[] = [];
let allInsightsOutput = '';
let stderrOutput = '';
proc.stdout?.on('data', (data: Buffer) => {
const text = data.toString();
@@ -159,8 +160,9 @@ export class InsightsExecutor extends EventEmitter {
proc.stderr?.on('data', (data: Buffer) => {
const text = data.toString();
// Collect stderr for rate limit detection too
// Collect stderr for rate limit detection and error reporting
allInsightsOutput = (allInsightsOutput + text).slice(-10000);
stderrOutput = (stderrOutput + text).slice(-2000);
console.error('[Insights]', text);
});
@@ -196,7 +198,11 @@ export class InsightsExecutor extends EventEmitter {
toolsUsed
});
} else {
const error = `Process exited with code ${code}`;
// Include stderr output in error message for debugging
const stderrSummary = stderrOutput.trim()
? `\n\nError output:\n${stderrOutput.slice(-500)}`
: '';
const error = `Process exited with code ${code}${stderrSummary}`;
this.emit('stream-chunk', projectId, {
type: 'error',
error