Merge branch 'develop' into enhance-workflows
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -42,13 +42,36 @@ To install:
|
||||
================================================================================
|
||||
`;
|
||||
|
||||
/**
|
||||
* Get electron version from package.json
|
||||
*/
|
||||
function getElectronVersion() {
|
||||
const pkgPath = path.join(__dirname, '..', 'package.json');
|
||||
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
||||
const electronVersion = pkg.devDependencies?.electron || pkg.dependencies?.electron;
|
||||
if (!electronVersion) {
|
||||
return null;
|
||||
}
|
||||
// Strip leading ^ or ~ from version
|
||||
return electronVersion.replace(/^[\^~]/, '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Run electron-rebuild
|
||||
*/
|
||||
function runElectronRebuild() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const npx = isWindows ? 'npx.cmd' : 'npx';
|
||||
const child = spawn(npx, ['electron-rebuild'], {
|
||||
const electronVersion = getElectronVersion();
|
||||
const args = ['electron-rebuild'];
|
||||
|
||||
// Explicitly pass electron version if detected
|
||||
if (electronVersion) {
|
||||
args.push('-v', electronVersion);
|
||||
console.log(`[postinstall] Using Electron version: ${electronVersion}`);
|
||||
}
|
||||
|
||||
const child = spawn(npx, args, {
|
||||
stdio: 'inherit',
|
||||
shell: isWindows,
|
||||
cwd: path.join(__dirname, '..'),
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -277,7 +277,7 @@ const DroppableColumn = memo(function DroppableColumn({ status, tasks, onTaskCli
|
||||
);
|
||||
}, droppableColumnPropsAreEqual);
|
||||
|
||||
export function KanbanBoard({ tasks, onTaskClick, onNewTaskClick }: KanbanBoardProps) {
|
||||
export function KanbanBoard({ tasks, onTaskClick, onNewTaskClick, onRefresh, isRefreshing }: KanbanBoardProps) {
|
||||
const { t } = useTranslation('tasks');
|
||||
const [activeTask, setActiveTask] = useState<Task | null>(null);
|
||||
const [overColumnId, setOverColumnId] = useState<string | null>(null);
|
||||
@@ -412,6 +412,21 @@ export function KanbanBoard({ tasks, onTaskClick, onNewTaskClick }: KanbanBoardP
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
{/* Kanban header with refresh button */}
|
||||
{onRefresh && (
|
||||
<div className="flex items-center justify-end px-6 pt-4 pb-2">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={onRefresh}
|
||||
disabled={isRefreshing}
|
||||
className="gap-2 text-muted-foreground hover:text-foreground"
|
||||
>
|
||||
<RefreshCw className={cn("h-4 w-4", isRefreshing && "animate-spin")} />
|
||||
{isRefreshing ? 'Refreshing...' : 'Refresh Tasks'}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{/* Kanban columns */}
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
|
||||
Reference in New Issue
Block a user