Skip to content
Open
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
42 changes: 42 additions & 0 deletions apps/server/src/git/Layers/GitCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const PREPARED_COMMIT_PATCH_MAX_OUTPUT_BYTES = 49_000;
const RANGE_COMMIT_SUMMARY_MAX_OUTPUT_BYTES = 19_000;
const RANGE_DIFF_SUMMARY_MAX_OUTPUT_BYTES = 19_000;
const RANGE_DIFF_PATCH_MAX_OUTPUT_BYTES = 59_000;
const WORKING_TREE_DIFF_MAX_OUTPUT_BYTES = 512_000;
const WORKSPACE_FILES_MAX_OUTPUT_BYTES = 16 * 1024 * 1024;
const GIT_CHECK_IGNORE_MAX_STDIN_BYTES = 256 * 1024;
const STATUS_UPSTREAM_REFRESH_INTERVAL = Duration.seconds(15);
Expand Down Expand Up @@ -1602,6 +1603,46 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {
},
);

const readWorkingTreeDiff: GitCoreShape["readWorkingTreeDiff"] = Effect.fn("readWorkingTreeDiff")(
function* (cwd) {
// Check whether the repository has any commits yet.
const hasCommits = yield* executeGit(
"GitCore.readWorkingTreeDiff.hasCommits",
cwd,
["rev-parse", "HEAD"],
{ allowNonZeroExit: true, timeoutMs: 5_000, maxOutputBytes: 256 },
).pipe(Effect.map((result) => result.code === 0));

if (hasCommits) {
// Standard case: diff HEAD covers staged + unstaged changes on tracked files.
const trackedDiff = yield* runGitStdoutWithOptions(
"GitCore.readWorkingTreeDiff.trackedDiff",
cwd,
["diff", "HEAD", "--patch", "--minimal", "--no-color"],
{
maxOutputBytes: WORKING_TREE_DIFF_MAX_OUTPUT_BYTES,
truncateOutputAtMaxBytes: true,
},
);

return trackedDiff;
}

// No commits yet: show staged changes (initial add).
const stagedDiff = yield* runGitStdoutWithOptions(
"GitCore.readWorkingTreeDiff.stagedDiff",
cwd,
["diff", "--cached", "--patch", "--minimal", "--no-color"],
{
maxOutputBytes: WORKING_TREE_DIFF_MAX_OUTPUT_BYTES,
truncateOutputAtMaxBytes: true,
},
);

return stagedDiff;
},
);

const readConfigValue: GitCoreShape["readConfigValue"] = (cwd, key) =>
runGitStdout("GitCore.readConfigValue", cwd, ["config", "--get", key], true).pipe(
Effect.map((stdout) => stdout.trim()),
Expand Down Expand Up @@ -2134,6 +2175,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {
pushCurrentBranch,
pullCurrentBranch,
readRangeContext,
readWorkingTreeDiff,
readConfigValue,
isInsideWorkTree,
listWorkspaceFiles,
Expand Down
5 changes: 5 additions & 0 deletions apps/server/src/git/Services/GitCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ export interface GitCoreShape {
baseBranch: string,
) => Effect.Effect<GitRangeContext, GitCommandError>;

/**
* Read a unified patch of working tree changes (staged + unstaged) on tracked files against HEAD.
*/
readonly readWorkingTreeDiff: (cwd: string) => Effect.Effect<string, GitCommandError>;

/**
* Read a Git config value from the local repository.
*/
Expand Down
6 changes: 6 additions & 0 deletions apps/server/src/ws.ts
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,12 @@ const WsRpcLayer = WsRpcGroup.toLayer(
git.initRepo(input).pipe(Effect.tap(() => refreshGitStatus(input.cwd))),
{ "rpc.aggregate": "git" },
),
[WS_METHODS.gitWorkingTreeDiff]: (input) =>
observeRpcEffect(
WS_METHODS.gitWorkingTreeDiff,
git.readWorkingTreeDiff(input.cwd).pipe(Effect.map((diff) => ({ diff }))),
{ "rpc.aggregate": "git" },
),
[WS_METHODS.terminalOpen]: (input) =>
observeRpcEffect(WS_METHODS.terminalOpen, terminalManager.open(input), {
"rpc.aggregate": "terminal",
Expand Down
Loading
Loading