11import { IpcMain } from 'electron' ;
22import { mkdir } from 'fs/promises' ;
3+ import path from 'path' ;
34import type { AppServices } from './types' ;
45import type { CreateProjectRequest , UpdateProjectRequest } from '../../../frontend/src/types/project' ;
56import { scriptExecutionTracker } from '../services/scriptExecutionTracker' ;
@@ -114,13 +115,19 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices)
114115 await mkdir ( pathResolver . toFileSystem ( actualPath ) , { recursive : true } ) ;
115116 console . log ( '[Main] Ensured project directory exists' ) ;
116117
117- // Check if it's a git repository
118+ // Check if it's a git repository (use fs to avoid cmd.exe encoding issues with Chinese paths)
119+ const fsPath = pathResolver . toFileSystem ( actualPath ) ;
120+ const gitDirPath = path . join ( fsPath , '.git' ) ;
118121 try {
119- commandRunner . exec ( 'git rev-parse --is-inside-work-tree' , actualPath , { silent : true } ) ;
120- isGitRepo = true ;
121- console . log ( '[Main] Directory is already a git repository' ) ;
122+ const stat = await import ( 'fs' ) . then ( fs => fs . existsSync ( gitDirPath ) ) ;
123+ if ( stat ) {
124+ isGitRepo = true ;
125+ console . log ( '[Main] Directory is already a git repository (.git found)' ) ;
126+ } else {
127+ console . log ( '[Main] Directory is not a git repository, initializing...' ) ;
128+ }
122129 } catch {
123- console . log ( '[Main] Directory is not a git repository, initializing...' ) ;
130+ console . log ( '[Main] Could not check git status, will try initializing...' ) ;
124131 }
125132
126133 // Initialize git if needed
@@ -133,8 +140,31 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices)
133140 commandRunner . exec ( `git checkout -b ${ branchName } ` , actualPath ) ;
134141 console . log ( `[Main] Created and checked out branch: ${ branchName } ` ) ;
135142
136- // Add all existing files so worktrees will have them
137- commandRunner . exec ( 'git add -A' , actualPath ) ;
143+ // Create default .gitignore for research projects (skip large data/model files)
144+ const gitignorePath = path . join ( fsPath , '.gitignore' ) ;
145+ const fs = await import ( 'fs' ) ;
146+ if ( ! fs . existsSync ( gitignorePath ) ) {
147+ fs . writeFileSync ( gitignorePath , [
148+ '# Data files' ,
149+ '*.csv' , '*.xlsx' , '*.parquet' , '*.feather' , '*.sqlite' , '*.db' ,
150+ '# Model weights' ,
151+ '*.pth' , '*.pt' , '*.h5' , '*.pkl' , '*.onnx' , '*.safetensors' ,
152+ '# GIS / Remote sensing' ,
153+ '*.tif' , '*.tiff' , '*.shp' , '*.dbf' , '*.shx' , '*.prj' , '*.gpkg' , '*.img' , '*.hdf' , '*.nc' ,
154+ '# Large binary files' ,
155+ '*.npy' , '*.npz' , '*.zip' , '*.tar' , '*.gz' , '*.7z' , '*.rar' ,
156+ '# Cache & IDE' ,
157+ '__pycache__/' , '.venv/' , 'node_modules/' , '.ipynb_checkpoints/' ,
158+ '.idea/' , '.vscode/' , '*.swp' ,
159+ '# System' ,
160+ '.DS_Store' , 'Thumbs.db' ,
161+ ''
162+ ] . join ( '\n' ) , 'utf-8' ) ;
163+ console . log ( '[Main] Created default .gitignore for research project' ) ;
164+ }
165+
166+ // Add all existing files (with .gitignore filtering) so worktrees will have them
167+ commandRunner . exec ( 'git add -A' , actualPath , { maxBuffer : 50 * 1024 * 1024 } ) ;
138168 commandRunner . exec ( 'git commit -m "Initial commit" --allow-empty' , actualPath , { env : GIT_ATTRIBUTION_ENV } ) ;
139169 console . log ( '[Main] Created initial commit with existing files' ) ;
140170 } catch ( error ) {
0 commit comments