Skip to content

Commit 45046cb

Browse files
zoidbergclawdclaude
andcommitted
Bundle MinGit for Windows to eliminate Git dependency
Claude Code CLI requires git-bash on Windows. On fresh installs without Git, cli.js exits with code 1. Bundle MinGit (~39MB) in the Windows installer so the app works out of the box. - Add scripts/bundle-mingit.mjs: downloads MinGit, copies sh.exe to bash.exe (MinGit's sh.exe IS GNU bash 5.2 in POSIX mode) - electron-builder.js: include build/mingit/ as extraResource on Windows - electron/main.ts: set CLAUDE_CODE_GIT_BASH_PATH and add git to PATH from bundled MinGit before starting the backend - agentRunner.ts: log CLAUDE_CODE_GIT_BASH_PATH in diagnostics - Bump version to 0.2.4 Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 1c71da8 commit 45046cb

8 files changed

Lines changed: 82 additions & 4 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ electron/dist/
3939
backend/dist/
4040
build/icon.ico
4141
build/icon.icns
42+
build/mingit/
43+
build/mingit.zip
4244

4345
# Video scripts
4446
docs/video-scripts/

backend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "elisa-backend",
3-
"version": "0.2.3",
3+
"version": "0.2.4",
44
"private": true,
55
"license": "MIT",
66
"type": "module",

backend/src/services/agentRunner.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,7 @@ export class AgentRunner {
200200
`Platform: ${process.platform} ${process.arch}`,
201201
`API key: ${process.env.ANTHROPIC_API_KEY ? `set (${process.env.ANTHROPIC_API_KEY.length} chars)` : 'NOT SET'}`,
202202
`ELISA_RESOURCES_PATH: ${process.env.ELISA_RESOURCES_PATH ?? 'not set'}`,
203+
`CLAUDE_CODE_GIT_BASH_PATH: ${process.env.CLAUDE_CODE_GIT_BASH_PATH ?? 'not set'}`,
203204
]);
204205

205206
const conversation = query({

electron-builder.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,10 @@ module.exports = {
3535
from: 'devices/_shared',
3636
to: 'devices/_shared',
3737
},
38+
// MinGit: bundled Git + bash for Windows (Claude Code CLI requires git-bash)
39+
...(process.platform === 'win32' && fs.existsSync(path.join(__dirname, 'build', 'mingit', 'cmd', 'git.exe'))
40+
? [{ from: 'build/mingit', to: 'mingit' }]
41+
: []),
3842
],
3943
win: {
4044
target: 'nsis',

electron/main.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,19 @@ async function startBackend(): Promise<void> {
183183
// Production: tell the backend where packaged resources live
184184
process.env.ELISA_RESOURCES_PATH = process.resourcesPath;
185185

186+
// MinGit: set up bundled Git + bash for Windows so Claude Code CLI works
187+
// without a system Git installation.
188+
if (process.platform === 'win32') {
189+
const mingitDir = path.join(process.resourcesPath, 'mingit');
190+
const bashExe = path.join(mingitDir, 'usr', 'bin', 'bash.exe');
191+
if (require('fs').existsSync(bashExe)) {
192+
process.env.CLAUDE_CODE_GIT_BASH_PATH = bashExe;
193+
const gitCmd = path.join(mingitDir, 'cmd');
194+
const gitUsrBin = path.join(mingitDir, 'usr', 'bin');
195+
process.env.PATH = `${gitCmd};${gitUsrBin};${process.env.PATH}`;
196+
}
197+
}
198+
186199
const backendDist = path.join(process.resourcesPath, 'backend-dist');
187200

188201
// Production: start the bundled backend in-process

frontend/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "frontend",
33
"private": true,
4-
"version": "0.2.3",
4+
"version": "0.2.4",
55
"license": "MIT",
66
"type": "module",
77
"scripts": {

package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "elisa",
3-
"version": "0.2.3",
3+
"version": "0.2.4",
44
"private": true,
55
"license": "MIT",
66
"author": "Elisa",
@@ -16,7 +16,8 @@
1616
"build:backend:deps": "node scripts/bundle-backend-deps.mjs",
1717
"test:electron": "vitest run --config electron/vitest.config.ts",
1818
"build:electron": "tsc -p electron/tsconfig.json",
19-
"build": "npm run build:frontend && npm run build:backend && npm run build:backend:deps && npm run build:electron",
19+
"build:mingit": "node scripts/bundle-mingit.mjs",
20+
"build": "npm run build:frontend && npm run build:backend && npm run build:backend:deps && npm run build:mingit && npm run build:electron",
2021
"pack": "npm run build && electron-builder --dir",
2122
"dist": "npm run build && electron-builder",
2223
"dist:win": "npm run build && electron-builder --win",

scripts/bundle-mingit.mjs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**
2+
* Download and prepare MinGit for Windows bundling.
3+
*
4+
* MinGit provides git + POSIX tools needed by Claude Code CLI.
5+
* MinGit's sh.exe IS GNU bash (same binary, POSIX mode by default),
6+
* so we copy it to bash.exe to satisfy Claude Code's requirement.
7+
*
8+
* Only runs on Windows. Skipped on other platforms.
9+
*/
10+
11+
import { existsSync, mkdirSync, cpSync, copyFileSync, rmSync } from 'fs';
12+
import { execSync } from 'child_process';
13+
import { join } from 'path';
14+
15+
if (process.platform !== 'win32') {
16+
console.log('MinGit bundling skipped (not Windows)');
17+
process.exit(0);
18+
}
19+
20+
const MINGIT_VERSION = '2.53.0.2';
21+
const MINGIT_URL = `https://github.com/git-for-windows/git/releases/download/v2.53.0.windows.2/MinGit-${MINGIT_VERSION}-64-bit.zip`;
22+
const DEST_DIR = join(process.cwd(), 'build', 'mingit');
23+
const CACHE_ZIP = join(process.cwd(), 'build', 'mingit.zip');
24+
25+
// Skip if already extracted
26+
if (existsSync(join(DEST_DIR, 'cmd', 'git.exe'))) {
27+
console.log('MinGit already present, skipping download');
28+
process.exit(0);
29+
}
30+
31+
mkdirSync(join(process.cwd(), 'build'), { recursive: true });
32+
33+
// Download
34+
if (!existsSync(CACHE_ZIP)) {
35+
console.log(`Downloading MinGit ${MINGIT_VERSION}...`);
36+
execSync(`curl -sL "${MINGIT_URL}" -o "${CACHE_ZIP}"`, { stdio: 'inherit' });
37+
}
38+
39+
// Extract
40+
console.log('Extracting MinGit...');
41+
rmSync(DEST_DIR, { recursive: true, force: true });
42+
mkdirSync(DEST_DIR, { recursive: true });
43+
execSync(
44+
`powershell.exe -NoProfile -Command "Expand-Archive -Path '${CACHE_ZIP}' -DestinationPath '${DEST_DIR}' -Force"`,
45+
{ stdio: 'inherit' },
46+
);
47+
48+
// MinGit's sh.exe is GNU bash in POSIX mode. Copy it to bash.exe so
49+
// Claude Code CLI can find it via CLAUDE_CODE_GIT_BASH_PATH.
50+
const shExe = join(DEST_DIR, 'usr', 'bin', 'sh.exe');
51+
const bashExe = join(DEST_DIR, 'usr', 'bin', 'bash.exe');
52+
if (existsSync(shExe) && !existsSync(bashExe)) {
53+
copyFileSync(shExe, bashExe);
54+
console.log('Copied sh.exe -> bash.exe');
55+
}
56+
57+
console.log(`MinGit ${MINGIT_VERSION} ready at ${DEST_DIR}`);

0 commit comments

Comments
 (0)