Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function DeleteToolView({
<LoadingIcon icon={Trash} isLoading={isLoading} />
{filePath && <FileMentionChip filePath={filePath} />}
{deletedLines !== null && (
<Text size="1">
<Text size="1" className="font-mono">
<span className="text-red-11">-{deletedLines}</span>
</Text>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ export function EditToolView({
<LoadingIcon icon={PencilSimple} isLoading={isLoading} />
{filePath && <FileMentionChip filePath={filePath} />}
{diffStats && (
<Text size="1">
<Text size="1" className="font-mono">
<span className="text-green-11">+{diffStats.added}</span>{" "}
<span className="text-red-11">-{diffStats.removed}</span>
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export const FileMentionChip = memo(function FileMentionChip({
>
<Text size="1">
<FileIcon filename={filename} size={12} />
{filename}
<span className="font-mono">{filename}</span>
</Text>
</Flex>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,14 @@ export function MoveToolView({
wasCancelled={wasCancelled}
>
{title ||
(sourcePath && destPath
? `Move ${getFilename(sourcePath)} → ${getFilename(destPath)}`
: "Move file")}
(sourcePath && destPath ? (
<>
Move <span className="font-mono">{getFilename(sourcePath)}</span> →{" "}
<span className="font-mono">{getFilename(destPath)}</span>
</>
) : (
"Move file"
))}
</ToolRow>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@ export function SearchToolView({
isExpandable
isExpanded={isExpanded}
/>
<ToolTitle>{title || "Search"}</ToolTitle>
<ToolTitle className="truncate">
<span className="font-mono">{title || "Search"}</span>
</ToolTitle>
<ToolTitle className="shrink-0 whitespace-nowrap">
{resultCount} {resultCount === 1 ? "result" : "results"}
</ToolTitle>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export function ThinkToolView({

<Box className="border-gray-6 border-t px-3 py-2">
<Text asChild size="1" className="text-gray-11">
<pre className="m-0 whitespace-pre-wrap break-all">
<pre className="m-0 whitespace-pre-wrap break-all font-mono">
{displayedContent}
</pre>
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export const ThoughtView = memo(function ThoughtView({
<Box className="mt-1 ml-5 max-w-4xl overflow-hidden rounded-lg border border-gray-6">
<Box className="max-h-64 overflow-auto px-3 py-2">
<Text asChild size="1" className="text-gray-11">
<pre className="m-0 whitespace-pre-wrap break-all">
<pre className="m-0 whitespace-pre-wrap break-all font-mono">
{displayedContent}
</pre>
</Text>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,9 @@ export function ContentPre({ children }: { children: React.ReactNode }) {
return (
<Box className="max-h-64 overflow-auto px-3 py-2">
<Text asChild size="1" className="text-gray-11">
<pre className="m-0 whitespace-pre-wrap break-all">{children}</pre>
<pre className="m-0 whitespace-pre-wrap break-all font-mono">
{children}
</pre>
</Text>
</Box>
);
Expand Down
31 changes: 27 additions & 4 deletions packages/git/src/operation-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,29 @@ import { createGitClient, type GitClient } from "./client";
import { removeLock, waitForUnlock } from "./lock-detector";
import { AsyncReaderWriterLock } from "./rw-lock";

/**
* Returns process.env with Electron/Chromium variables cleaned so that
* child processes spawned by git hooks (e.g. biome via lint-staged) don't
* crash trying to initialise GPU subsystems.
*
* The agent service symlinks `node → Electron binary` and prepends it to
* PATH. If ELECTRON_RUN_AS_NODE is missing, that binary starts as a full
* Chromium browser (GPU init → SIGTRAP crash). We strip most ELECTRON_/
* CHROME_ vars but explicitly keep ELECTRON_RUN_AS_NODE=1 so any such
* shim still behaves as plain Node.js.
*/
function getCleanEnv(): Record<string, string> {
const env: Record<string, string> = {};
for (const [key, value] of Object.entries(process.env)) {
if (value === undefined) continue;
if (key === "ELECTRON_RUN_AS_NODE") continue;
if (key.startsWith("ELECTRON_") || key.startsWith("CHROME_")) continue;
env[key] = value;
}
env.ELECTRON_RUN_AS_NODE = "1";
return env;
}

interface RepoState {
lock: AsyncReaderWriterLock;
client: GitClient;
Expand Down Expand Up @@ -62,11 +85,11 @@ class GitOperationManagerImpl {
abortSignal: options.signal,
});
return operation(
scopedGit.env({ ...process.env, GIT_OPTIONAL_LOCKS: "0" }),
scopedGit.env({ ...getCleanEnv(), GIT_OPTIONAL_LOCKS: "0" }),
);
}

const git = state.client.env({ ...process.env, GIT_OPTIONAL_LOCKS: "0" });
const git = state.client.env({ ...getCleanEnv(), GIT_OPTIONAL_LOCKS: "0" });
return operation(git);
}

Expand All @@ -93,10 +116,10 @@ class GitOperationManagerImpl {
const scopedGit = createGitClient(repoPath, {
abortSignal: options.signal,
});
return await operation(scopedGit.env(process.env));
return await operation(scopedGit.env(getCleanEnv()));
}

return await operation(state.client.env(process.env));
return await operation(state.client.env(getCleanEnv()));
} catch (error) {
if (options?.signal?.aborted) {
await removeLock(repoPath).catch(() => {});
Expand Down
Loading