Skip to content

Commit aefa7d9

Browse files
committed
Release v0.0.35
## What's New ### Features - **CLI Command Support** — Added CLI command support and existing API key detection - **Auto-Advance Setting** — New option to auto-advance through workspace archive navigation ### Improvements & Fixes - Improved Windows PATH resolution for packaged apps
1 parent b9fa4c5 commit aefa7d9

File tree

2 files changed

+74
-13
lines changed

2 files changed

+74
-13
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "21st-desktop",
3-
"version": "0.0.34",
3+
"version": "0.0.35",
44
"private": true,
55
"description": "1Code - UI for parallel work with AI agents",
66
"author": {

src/main/lib/git/shell-env.ts

Lines changed: 73 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
execFile,
44
} from "node:child_process";
55
import os from "node:os";
6+
import path from "node:path";
67
import { promisify } from "node:util";
78

89
const execFileAsync = promisify(execFile);
@@ -19,14 +20,56 @@ let pathFixAttempted = false;
1920
let pathFixSucceeded = false;
2021

2122
/**
22-
* Gets the full shell environment by spawning a login shell.
23-
* This captures PATH and other environment variables set in shell profiles
24-
* which includes tools like git-lfs installed via homebrew.
23+
* Build Windows PATH by combining process.env.PATH with common install locations.
24+
* This ensures packaged apps on Windows can find user-installed tools.
25+
*/
26+
function buildWindowsPath(): string {
27+
const paths: string[] = [];
28+
const pathSeparator = ";";
29+
30+
// Start with existing PATH from process.env
31+
if (process.env.PATH) {
32+
paths.push(...process.env.PATH.split(pathSeparator).filter(Boolean));
33+
}
34+
35+
// Add Windows-specific common paths
36+
const commonPaths = [
37+
// User-local installations (where tools like Claude CLI, git-lfs are often installed)
38+
path.join(os.homedir(), ".local", "bin"),
39+
// Git for Windows default location
40+
"C:\\Program Files\\Git\\cmd",
41+
"C:\\Program Files\\Git\\bin",
42+
// System paths (usually already in PATH, but ensure they're present)
43+
path.join(process.env.SystemRoot || "C:\\Windows", "System32"),
44+
path.join(process.env.SystemRoot || "C:\\Windows"),
45+
];
46+
47+
// Add common paths that aren't already in PATH
48+
for (const commonPath of commonPaths) {
49+
const normalizedPath = path.normalize(commonPath);
50+
// Case-insensitive check for Windows
51+
const normalizedLower = normalizedPath.toLowerCase();
52+
const alreadyExists = paths.some(
53+
(p) => path.normalize(p).toLowerCase() === normalizedLower,
54+
);
55+
if (!alreadyExists) {
56+
paths.push(normalizedPath);
57+
}
58+
}
59+
60+
return paths.join(pathSeparator);
61+
}
62+
63+
/**
64+
* Gets the full shell environment with proper PATH for all platforms.
65+
*
66+
* - **Windows**: Derives PATH from process.env + common install locations (no shell spawn)
67+
* - **macOS/Linux**: Spawns login shell to capture PATH from shell profiles
2568
*
26-
* Uses -lc (login, command) instead of -ilc to avoid interactive prompts
27-
* and TTY issues from dotfiles expecting a terminal.
69+
* This captures PATH and other environment variables needed to find user-installed tools
70+
* like git-lfs (homebrew on macOS) or Claude CLI (user-local on Windows).
2871
*
29-
* Results are cached for 1 minute to avoid spawning shells repeatedly.
72+
* Results are cached for 1 minute to avoid repeated operations.
3073
*/
3174
export async function getShellEnvironment(): Promise<Record<string, string>> {
3275
const now = Date.now();
@@ -36,20 +79,38 @@ export async function getShellEnvironment(): Promise<Record<string, string>> {
3679
return { ...cachedEnv };
3780
}
3881

39-
// On Windows, use process.env directly (no Unix shell available)
82+
// Windows: derive PATH without shell invocation
83+
// Git Bash PATH doesn't include Windows user paths, so we build it manually
4084
if (process.platform === "win32") {
41-
const fallback: Record<string, string> = {};
42-
for (const [key, value] of Object.entries(process.env)) {
85+
console.log(
86+
"[shell-env] Windows detected, deriving PATH without shell invocation",
87+
);
88+
const env: Record<string, string> = {
89+
...process.env,
90+
PATH: buildWindowsPath(),
91+
HOME: os.homedir(),
92+
USER: os.userInfo().username,
93+
USERPROFILE: os.homedir(),
94+
};
95+
96+
// Ensure all values are strings
97+
const stringEnv: Record<string, string> = {};
98+
for (const [key, value] of Object.entries(env)) {
4399
if (typeof value === "string") {
44-
fallback[key] = value;
100+
stringEnv[key] = value;
45101
}
46102
}
47-
cachedEnv = fallback;
103+
104+
cachedEnv = stringEnv;
48105
cacheTime = now;
49106
isFallbackCache = false;
50-
return { ...fallback };
107+
console.log(
108+
`[shell-env] Built Windows environment with ${Object.keys(stringEnv).length} vars`,
109+
);
110+
return { ...stringEnv };
51111
}
52112

113+
// macOS/Linux: spawn login shell to get full environment
53114
const shell =
54115
process.env.SHELL ||
55116
(process.platform === "darwin" ? "/bin/zsh" : "/bin/bash");

0 commit comments

Comments
 (0)