Keep diff renderer dependency in plugin

This commit is contained in:
Dotta committed 2026-05-16 07:47:15 -05:00
1 parent d9a59827fd
commit 8baca513c0
3 files changed
+56 -530

No files matched your search

-1
View File
@@ -45,7 +45,6 @@
"@paperclipai/adapter-pi-local": "workspace:*",
"@paperclipai/adapter-utils": "workspace:*",
"@paperclipai/shared": "workspace:*",
"@pierre/diffs": "^1.1.22",
"@radix-ui/react-slot": "^1.2.4",
"@tailwindcss/typography": "^0.5.19",
"@tanstack/react-query": "^5.90.21",
-276
View File
@@ -1,276 +0,0 @@
import { parsePatchFiles } from "@pierre/diffs";
import type { FileDiffMetadata } from "@pierre/diffs";
const smallDiffPatch = `diff --git a/src/pagination.ts b/src/pagination.ts
index 6c2a1f4..e91d2ac 100644
--- a/src/pagination.ts
+++ b/src/pagination.ts
@@ -1,8 +1,12 @@
export type PageRequest = {
limit: number;
+ cursor?: string;
offset: number;
};
export function buildOffset(offset: number, limit: number) {
- return { offset, limit };
+ return {
+ offset,
+ limit,
+ hasMore: limit > 0,
+ };
}
`;
const largeDiffPatch = `diff --git a/tmp/pierre-large-old.ts b/tmp/pierre-large-new.ts
index 6ea4ef1..9449233 100644
--- a/tmp/pierre-large-old.ts
+++ b/tmp/pierre-large-new.ts
@@ -1,160 +1,163 @@
export const value_001 = '1';
export const value_002 = '2';
-export const value_003 = '3';
+export const value_003 = '6';
export const value_004 = '4';
export const value_005 = '5';
-export const value_006 = '6';
+export const value_006 = '12';
export const value_007 = '7';
export const value_008 = '8';
-export const value_009 = '9';
+export const value_009 = '18';
export const value_010 = '10';
export const value_011 = '11';
-export const value_012 = '12';
+export const value_012 = '24';
export const value_013 = '13';
export const value_014 = '14';
-export const value_015 = '15';
+export const value_015 = '30';
export const value_016 = '16';
export const value_017 = '17';
-export const value_018 = '18';
+export const value_018 = '36';
export const value_019 = '19';
export const value_020 = '20';
+export function isEven(n: number) {
+ return n % 2 === 0;
+}
-export const value_021 = '21';
+export const value_021 = '42';
export const value_022 = '22';
export const value_023 = '23';
-export const value_024 = '24';
+export const value_024 = '48';
export const value_025 = '25';
export const value_026 = '26';
-export const value_027 = '27';
+export const value_027 = '54';
export const value_028 = '28';
export const value_029 = '29';
-export const value_030 = '30';
+export const value_030 = '60';
export const value_031 = '31';
export const value_032 = '32';
-export const value_033 = '33';
+export const value_033 = '66';
export const value_034 = '34';
export const value_035 = '35';
-export const value_036 = '36';
+export const value_036 = '72';
export const value_037 = '37';
export const value_038 = '38';
-export const value_039 = '39';
+export const value_039 = '78';
export const value_040 = '40';
export const value_041 = '41';
-export const value_042 = '42';
+export const value_042 = '84';
export const value_043 = '43';
export const value_044 = '44';
-export const value_045 = '45';
+export const value_045 = '90';
export const value_046 = '46';
export const value_047 = '47';
-export const value_048 = '48';
+export const value_048 = '96';
export const value_049 = '49';
export const value_050 = '50';
-export const value_051 = '51';
+export const value_051 = '102';
export const value_052 = '52';
export const value_053 = '53';
-export const value_054 = '54';
+export const value_054 = '108';
export const value_055 = '55';
export const value_056 = '56';
-export const value_057 = '57';
+export const value_057 = '114';
export const value_058 = '58';
export const value_059 = '59';
-export const value_060 = '60';
+export const value_060 = '120';
export const value_061 = '61';
export const value_062 = '62';
-export const value_063 = '63';
+export const value_063 = '126';
export const value_064 = '64';
export const value_065 = '65';
-export const value_066 = '66';
+export const value_066 = '132';
export const value_067 = '67';
export const value_068 = '68';
-export const value_069 = '69';
+export const value_069 = '138';
export const value_070 = '70';
export const value_071 = '71';
-export const value_072 = '72';
+export const value_072 = '144';
export const value_073 = '73';
export const value_074 = '74';
-export const value_075 = '75';
+export const value_075 = '150';
export const value_076 = '76';
export const value_077 = '77';
-export const value_078 = '78';
+export const value_078 = '156';
export const value_079 = '79';
export const value_080 = '80';
-export const value_081 = '81';
+export const value_081 = '162';
export const value_082 = '82';
export const value_083 = '83';
-export const value_084 = '84';
+export const value_084 = '168';
export const value_085 = '85';
export const value_086 = '86';
-export const value_087 = '87';
+export const value_087 = '174';
export const value_088 = '88';
export const value_089 = '89';
-export const value_090 = '90';
+export const value_090 = '180';
export const value_091 = '91';
export const value_092 = '92';
-export const value_093 = '93';
+export const value_093 = '186';
export const value_094 = '94';
export const value_095 = '95';
-export const value_096 = '96';
+export const value_096 = '192';
export const value_097 = '97';
export const value_098 = '98';
-export const value_099 = '99';
+export const value_099 = '198';
export const value_100 = '100';
export const value_101 = '101';
-export const value_102 = '102';
+export const value_102 = '204';
export const value_103 = '103';
export const value_104 = '104';
-export const value_105 = '105';
+export const value_105 = '210';
export const value_106 = '106';
export const value_107 = '107';
-export const value_108 = '108';
+export const value_108 = '216';
export const value_109 = '109';
export const value_110 = '110';
-export const value_111 = '111';
+export const value_111 = '222';
export const value_112 = '112';
export const value_113 = '113';
-export const value_114 = '114';
+export const value_114 = '228';
export const value_115 = '115';
export const value_116 = '116';
-export const value_117 = '117';
+export const value_117 = '234';
export const value_118 = '118';
export const value_119 = '119';
-export const value_120 = '120';
+export const value_120 = '240';
export const value_121 = '121';
export const value_122 = '122';
-export const value_123 = '123';
+export const value_123 = '246';
export const value_124 = '124';
export const value_125 = '125';
-export const value_126 = '126';
+export const value_126 = '252';
export const value_127 = '127';
export const value_128 = '128';
-export const value_129 = '129';
+export const value_129 = '258';
export const value_130 = '130';
export const value_131 = '131';
-export const value_132 = '132';
+export const value_132 = '264';
export const value_133 = '133';
export const value_134 = '134';
-export const value_135 = '135';
+export const value_135 = '270';
export const value_136 = '136';
export const value_137 = '137';
-export const value_138 = '138';
+export const value_138 = '276';
export const value_139 = '139';
export const value_140 = '140';
-export const value_141 = '141';
+export const value_141 = '282';
export const value_142 = '142';
export const value_143 = '143';
-export const value_144 = '144';
+export const value_144 = '288';
export const value_145 = '145';
export const value_146 = '146';
-export const value_147 = '147';
+export const value_147 = '294';
export const value_148 = '148';
export const value_149 = '149';
-export const value_150 = '150';
+export const value_150 = '300';
export const value_151 = '151';
export const value_152 = '152';
-export const value_153 = '153';
+export const value_153 = '306';
export const value_154 = '154';
export const value_155 = '155';
-export const value_156 = '156';
+export const value_156 = '312';
export const value_157 = '157';
export const value_158 = '158';
-export const value_159 = '159';
+export const value_159 = '318';
export const value_160 = '160';
`;
function parsePatchFilesOrEmpty(patch: string): FileDiffMetadata[] {
return parsePatchFiles(patch).flatMap((entry) => entry.files);
}
export type DiffRendererFixtureId = "small" | "large";
export interface DiffRendererFixture {
id: DiffRendererFixtureId;
label: string;
patch: string;
fileDiffs: FileDiffMetadata[];
}
export const DIFF_RENDERER_FIXTURES: DiffRendererFixture[] = [
{
id: "small",
label: "Small mixed edit fixture",
patch: smallDiffPatch,
fileDiffs: parsePatchFilesOrEmpty(smallDiffPatch),
},
{
id: "large",
label: "Large 160-line patch fixture",
patch: largeDiffPatch,
fileDiffs: parsePatchFilesOrEmpty(largeDiffPatch),
},
];
+56 -253
View File
@@ -1,30 +1,22 @@
import { useState } from "react";
import { FileDiff, PatchDiff } from "@pierre/diffs/react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { cn, formatDateTime } from "../lib/utils";
import { DIFF_RENDERER_FIXTURES, type DiffRendererFixtureId } from "../fixtures/diffRendererFixtures";
import { Identity } from "../components/Identity";
import { StatusBadge } from "../components/StatusBadge";
import { RunTranscriptView, type TranscriptDensity, type TranscriptMode } from "../components/transcript/RunTranscriptView";
import { runTranscriptFixtureEntries, runTranscriptFixtureMeta } from "../fixtures/runTranscriptFixtures";
import { ExternalLink, FlaskConical, LayoutPanelLeft, MonitorCog, PanelsTopLeft, RadioTower, GitCompare } from "lucide-react";
import { ExternalLink, FlaskConical, LayoutPanelLeft, MonitorCog, PanelsTopLeft, RadioTower } from "lucide-react";
type SurfaceId = "detail" | "live" | "dashboard" | "diffs";
type DiffComponentMode = "patch" | "file";
type DiffStyle = "unified" | "split";
type DiffOverflow = "scroll" | "wrap";
type DiffThemeType = "system" | "light" | "dark";
type SurfaceId = "detail" | "live" | "dashboard";
type SurfaceOption = {
const surfaceOptions: Array<{
id: SurfaceId;
label: string;
eyebrow: string;
description: string;
icon: typeof LayoutPanelLeft;
};
const surfaceOptions: SurfaceOption[] = [
}> = [
{
id: "detail",
label: "Run Detail",
@@ -46,13 +38,6 @@ const surfaceOptions: SurfaceOption[] = [
description: "The active-agents dashboard card, tuned for compact scanning while keeping the same transcript language.",
icon: PanelsTopLeft,
},
{
id: "diffs",
label: "Diff Renderer",
eyebrow: "@pierre/diffs",
description: "A spike harness for `PatchDiff` and `FileDiff` with realistic fixtures and rendering options.",
icon: GitCompare,
},
];
function previewEntries(surface: SurfaceId) {
@@ -175,9 +160,7 @@ function DashboardPreview({
<div className="flex items-center gap-2">
<span className={cn(
"inline-flex h-2.5 w-2.5 rounded-full",
streaming
? "bg-cyan-500 shadow-[0_0_0_6px_rgba(34,211,238,0.12)]"
: "bg-muted-foreground/35",
streaming ? "bg-cyan-500 shadow-[0_0_0_6px_rgba(34,211,238,0.12)]" : "bg-muted-foreground/35",
)} />
<Identity name={runTranscriptFixtureMeta.agentName} size="sm" />
</div>
@@ -207,111 +190,12 @@ function DashboardPreview({
);
}
function DiffRendererPreview({
fixtureId,
componentMode,
diffStyle,
overflow,
showLineNumbers,
disableBackground,
themeType,
}: {
fixtureId: DiffRendererFixtureId;
componentMode: DiffComponentMode;
diffStyle: DiffStyle;
overflow: DiffOverflow;
showLineNumbers: boolean;
disableBackground: boolean;
themeType: DiffThemeType;
}) {
const fixture = DIFF_RENDERER_FIXTURES.find((item) => item.id === fixtureId) ?? DIFF_RENDERER_FIXTURES[0];
const firstFileDiff = fixture.fileDiffs[0];
const options = {
diffStyle,
overflow,
disableLineNumbers: !showLineNumbers,
disableBackground,
themeType,
};
return (
<div className="overflow-hidden rounded-xl border border-border/70 bg-background/75 shadow-[0_24px_60px_rgba(15,23,42,0.08)]">
<div className="border-b border-border/60 bg-background/90 px-5 py-4">
<div className="flex flex-wrap items-center gap-2">
<Badge variant="outline" className="uppercase tracking-[0.18em] text-[10px]">
Diff Render
</Badge>
<span className="rounded-full border border-border/70 bg-background/70 px-2 py-1 text-[10px] text-muted-foreground">
{fixture.label}
</span>
</div>
<div className="mt-2 text-sm font-medium">
{componentMode === "patch" ? "PatchDiff" : "FileDiff"} • {diffStyle.toUpperCase()} • {fixture.fileDiffs.length} file(s)
</div>
</div>
<div className="max-h-[720px] overflow-hidden bg-[radial-gradient(circle_at_top_left,rgba(8,145,178,0.08),transparent_36%),radial-gradient(circle_at_bottom_right,rgba(245,158,11,0.10),transparent_28%)] p-5">
<div className="rounded-lg border border-border/70 bg-background/80 p-3">
{componentMode === "file" && !firstFileDiff ? (
<div className="rounded-lg border border-destructive/35 bg-destructive/10 px-3 py-2 text-sm text-destructive">
Parsed fixture did not produce a file diff payload for `FileDiff`.
</div>
) : componentMode === "patch" ? (
<PatchDiff patch={fixture.patch} options={options} />
) : (
<FileDiff fileDiff={firstFileDiff} options={options} />
)}
</div>
</div>
</div>
);
}
function ToggleButtonGroup<T extends string>({
selected,
options,
onSelect,
}: {
selected: T;
options: Array<{
id: T;
label: string;
}>;
onSelect: (next: T) => void;
}) {
return (
<div className="inline-flex rounded-full border border-border/70 bg-background/80 p-1">
{options.map((option) => (
<button
key={option.id}
type="button"
className={cn(
"rounded-full px-3 py-1 text-xs font-medium capitalize transition-colors",
selected === option.id ? "bg-accent text-foreground" : "text-muted-foreground hover:text-foreground",
)}
onClick={() => onSelect(option.id)}
>
{option.label}
</button>
))}
</div>
);
}
export function RunTranscriptUxLab() {
const [selectedSurface, setSelectedSurface] = useState<SurfaceId>("detail");
const [detailMode, setDetailMode] = useState<TranscriptMode>("nice");
const [streaming, setStreaming] = useState(true);
const [density, setDensity] = useState<TranscriptDensity>("comfortable");
const [diffComponentMode, setDiffComponentMode] = useState<DiffComponentMode>("file");
const [diffFixture, setDiffFixture] = useState<DiffRendererFixtureId>(DIFF_RENDERER_FIXTURES[0]?.id ?? "small");
const [diffStyle, setDiffStyle] = useState<DiffStyle>("unified");
const [diffOverflow, setDiffOverflow] = useState<DiffOverflow>("scroll");
const [diffShowLineNumbers, setDiffShowLineNumbers] = useState(true);
const [diffDisableBackground, setDiffDisableBackground] = useState(false);
const [diffThemeType, setDiffThemeType] = useState<DiffThemeType>("system");
const selected = surfaceOptions.find((option) => option.id === selectedSurface) ?? surfaceOptions[0];
return (
@@ -326,7 +210,7 @@ export function RunTranscriptUxLab() {
</div>
<h1 className="mt-4 text-2xl font-semibold tracking-tight">Run Transcript Fixtures</h1>
<p className="mt-2 text-sm text-muted-foreground">
Built from real Paperclip development data, with a focused spike surface for diff rendering controls.
Built from a real Paperclip development run, then sanitized so no secrets, local paths, or environment details survive into the fixture.
</p>
</div>
@@ -377,129 +261,58 @@ export function RunTranscriptUxLab() {
</p>
</div>
<div className="mb-5 flex flex-wrap items-center gap-2">
{selectedSurface === "diffs" ? (
<>
<span className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
Controls
</span>
<ToggleButtonGroup<DiffComponentMode>
selected={diffComponentMode}
options={[
{ id: "patch", label: "PatchDiff" },
{ id: "file", label: "FileDiff" },
]}
onSelect={setDiffComponentMode}
/>
<ToggleButtonGroup<DiffRendererFixtureId>
selected={diffFixture}
options={DIFF_RENDERER_FIXTURES.map((fixture) => ({
id: fixture.id,
label: fixture.label,
}))}
onSelect={setDiffFixture}
/>
<ToggleButtonGroup<DiffStyle>
selected={diffStyle}
options={[
{ id: "unified", label: "Unified" },
{ id: "split", label: "Split" },
]}
onSelect={setDiffStyle}
/>
<ToggleButtonGroup<DiffOverflow>
selected={diffOverflow}
options={[{ id: "scroll", label: "Scroll" }, { id: "wrap", label: "Wrap" }]}
onSelect={setDiffOverflow}
/>
<Button
variant="outline"
size="sm"
className="rounded-full"
onClick={() => setDiffShowLineNumbers((value) => !value)}
>
{diffShowLineNumbers ? "Hide" : "Show"} line numbers
</Button>
<Button
variant="outline"
size="sm"
className="rounded-full"
onClick={() => setDiffDisableBackground((value) => !value)}
>
{diffDisableBackground ? "Enable" : "Disable"} background
</Button>
<ToggleButtonGroup<DiffThemeType>
selected={diffThemeType}
options={[
{ id: "system", label: "Auto" },
{ id: "light", label: "Light" },
{ id: "dark", label: "Dark" },
]}
onSelect={setDiffThemeType}
/>
</>
) : (
<>
<span className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
Controls
</span>
<div className="inline-flex rounded-full border border-border/70 bg-background/80 p-1">
{(["nice", "raw"] as const).map((mode) => (
<button
key={mode}
type="button"
className={cn(
"rounded-full px-3 py-1 text-xs font-medium capitalize transition-colors",
detailMode === mode
? "bg-accent text-foreground"
: "text-muted-foreground hover:text-foreground",
)}
onClick={() => setDetailMode(mode)}
>
{mode}
</button>
))}
</div>
<div className="inline-flex rounded-full border border-border/70 bg-background/80 p-1">
{(["comfortable", "compact"] as const).map((nextDensity) => (
<button
key={nextDensity}
type="button"
className={cn(
"rounded-full px-3 py-1 text-xs font-medium capitalize transition-colors",
density === nextDensity
? "bg-accent text-foreground"
: "text-muted-foreground hover:text-foreground",
)}
onClick={() => setDensity(nextDensity)}
>
{nextDensity}
</button>
))}
</div>
<Button
variant="outline"
size="sm"
className="rounded-full"
onClick={() => setStreaming((value) => !value)}
>
{streaming ? "Show settled state" : "Show streaming state"}
</Button>
</>
)}
<div className="flex flex-wrap items-center gap-2">
<Badge variant="outline" className="rounded-full px-3 py-1 text-[10px] uppercase tracking-[0.18em]">
Source run {runTranscriptFixtureMeta.sourceRunId.slice(0, 8)}
</Badge>
<Badge variant="outline" className="rounded-full px-3 py-1 text-[10px] uppercase tracking-[0.18em]">
{runTranscriptFixtureMeta.issueIdentifier}
</Badge>
</div>
<Badge
</div>
<div className="mb-5 flex flex-wrap items-center gap-2">
<span className="text-[11px] font-semibold uppercase tracking-[0.18em] text-muted-foreground">
Controls
</span>
<div className="inline-flex rounded-full border border-border/70 bg-background/80 p-1">
{(["nice", "raw"] as const).map((mode) => (
<button
key={mode}
type="button"
className={cn(
"rounded-full px-3 py-1 text-xs font-medium capitalize transition-colors",
detailMode === mode ? "bg-accent text-foreground" : "text-muted-foreground hover:text-foreground",
)}
onClick={() => setDetailMode(mode)}
>
{mode}
</button>
))}
</div>
<div className="inline-flex rounded-full border border-border/70 bg-background/80 p-1">
{(["comfortable", "compact"] as const).map((nextDensity) => (
<button
key={nextDensity}
type="button"
className={cn(
"rounded-full px-3 py-1 text-xs font-medium capitalize transition-colors",
density === nextDensity ? "bg-accent text-foreground" : "text-muted-foreground hover:text-foreground",
)}
onClick={() => setDensity(nextDensity)}
>
{nextDensity}
</button>
))}
</div>
<Button
variant="outline"
className="mb-0.5 flex rounded-full px-3 py-1 text-[10px] uppercase tracking-[0.18em]"
size="sm"
className="rounded-full"
onClick={() => setStreaming((value) => !value)}
>
Source run {runTranscriptFixtureMeta.sourceRunId.slice(0, 8)}
</Badge>
<Badge
variant="outline"
className="mb-0.5 rounded-full px-3 py-1 text-[10px] uppercase tracking-[0.18em]"
>
{runTranscriptFixtureMeta.issueIdentifier}
</Badge>
{streaming ? "Show settled state" : "Show streaming state"}
</Button>
</div>
{selectedSurface === "detail" ? (
@@ -510,18 +323,8 @@ export function RunTranscriptUxLab() {
<div className={cn(density === "compact" && "max-w-4xl")}>
<LiveWidgetPreview streaming={streaming} mode={detailMode} density={density} />
</div>
) : selectedSurface === "dashboard" ? (
<DashboardPreview streaming={streaming} mode={detailMode} density={density} />
) : (
<DiffRendererPreview
fixtureId={diffFixture}
componentMode={diffComponentMode}
diffStyle={diffStyle}
overflow={diffOverflow}
showLineNumbers={diffShowLineNumbers}
disableBackground={diffDisableBackground}
themeType={diffThemeType}
/>
<DashboardPreview streaming={streaming} mode={detailMode} density={density} />
)}
</main>
</div>