Tools & Approvals
File Changes
Split review: a file tree on one side, hunks on the other — keep or revert each hunk, then apply the result.
2 variantsMIT
Preview
- src
- Modifiedcli.ts+4 −6
src/cli.ts
Line 1
1Removed: import yargs from "yargs";
2Removed: import { hideBin } from "yargs/helpers";
1Added: import { Command } from "commander";
32import { build } from "./commands/build";
Line 7
8Removed: yargs(hideBin(process.argv))
9Removed: .command("build <dir>", "Build a site", {}, build)
10Removed: .strict()
11Removed: .parse();
7Added: const program = new Command("pressd");
8Added: program.command("build <dir>").action(build);
9Added: program.parse();
Applying 2 of 2 hunks across 1 file
Installation
Copies the component into components/ui and installs its dependencies and theme tokens.
pnpm dlx shadcn@latest add https://tuffui.com/r/file-changes.jsonUsage
Pass your own data and wire the callbacks to your agent runtime.
import { useState } from "react";
import { FileChanges, type FileChange } from "@/components/ui/file-changes";
export function ReviewEdits({ changes }: { changes: FileChange[] }) {
const [applying, setApplying] = useState(false);
return (
<FileChanges
data={changes}
applying={applying}
onApply={async (selection) => {
// selection maps each file id to the hunk ids the user kept
setApplying(true);
await workspace.applyHunks(selection);
setApplying(false);
}}
onDiscard={() => workspace.revertAll()}
/>
);
}Props
| Prop | Type | Default | Description |
|---|---|---|---|
| data* | FileChange[] | — | Files the agent edited, each with its diff hunks. Every hunk needs an id. |
| view | "split" | "stacked" | "split" | Split puts a folder tree beside the hunks; stacked swaps the tree for a row of file tabs for narrow columns. |
| onApply* | (selection: HunkSelection) => void | — | Called with the hunk ids kept per file. Hunks left out were reverted. |
| onHunkChange | (fileId: string, hunkId: string, keep: boolean) => void | — | Called whenever a hunk is switched between Keep and Revert. |
| onDiscard | () => void | — | Shows a Discard all button. Throw away every change here. |
| applying | boolean | false | Puts the Apply button in its loading state. |
| selectedId / onSelectedChange | string / (fileId: string) => void | — | Control the open file. Leave out to let the component track it. |
| defaultSelectedId | string | — | File open on first render when uncontrolled. Defaults to the first file. |
| className | string | — | Extra classes for the root element. |
type FileChange = {
id: string;
path: string;
from?: string; // previous path when renamed
status: "added" | "modified" | "deleted" | "renamed";
hunks: DiffHunk[];
};
type DiffHunk = {
id: string;
oldStart: number;
newStart: number;
lines: { type: "add" | "remove" | "context"; text: string }[];
};
type HunkSelection = Record<string, string[]>; // file id → kept hunk ids