Skip to content

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.json

Usage

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

PropTypeDefaultDescription
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.
applyingbooleanfalsePuts the Apply button in its loading state.
selectedId / onSelectedChangestring / (fileId: string) => void—Control the open file. Leave out to let the component track it.
defaultSelectedIdstring—File open on first render when uncontrolled. Defaults to the first file.
classNamestring—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