From 0692e559817149e2d056842921b13a2a6ea4a96b Mon Sep 17 00:00:00 2001 From: claude code agent 227 Date: Sun, 21 Jun 2026 15:50:15 +0300 Subject: [PATCH] feat(git-sync): client 'Git sync' provenance badge + git in runtime image (Phase D) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - page-history history-item: a lastUpdatedSource==='git-sync' version renders a neutral gray 'Git sync' badge (git-merge icon), NOT the agent badge/deep-link (it is not an agent edit). +2 i18n keys. - Dockerfile: install git in the installer (runtime) stage โ€” VaultGit shells out to git, so assertGitAvailable() needs the binary at runtime. Client tsc clean. Co-Authored-By: Claude Opus 4.8 --- Dockerfile | 3 +- .../public/locales/en-US/translation.json | 2 ++ .../src/components/ui/git-sync-badge.tsx | 36 +++++++++++++++++++ .../page-history/components/history-item.tsx | 6 ++++ 4 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 apps/client/src/components/ui/git-sync-badge.tsx diff --git a/Dockerfile b/Dockerfile index 34e5b17f..0fd5dbf4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -17,8 +17,9 @@ RUN pnpm build FROM base AS installer +# git: required by the git-sync VaultGit (shells out to git) RUN apt-get update \ - && apt-get install -y --no-install-recommends curl bash \ + && apt-get install -y --no-install-recommends curl bash git \ && rm -rf /var/lib/apt/lists/* WORKDIR /app diff --git a/apps/client/public/locales/en-US/translation.json b/apps/client/public/locales/en-US/translation.json index a7f687c2..8f90979a 100644 --- a/apps/client/public/locales/en-US/translation.json +++ b/apps/client/public/locales/en-US/translation.json @@ -1204,6 +1204,8 @@ "Ran tool {{name}}": "Ran tool {{name}}", "AI-agent": "AI-agent", "Edited by AI agent on behalf of {{name}}": "Edited by AI agent on behalf of {{name}}", + "Git sync": "Git sync", + "Synced from Git on behalf of {{name}}": "Synced from Git on behalf of {{name}}", "Endpoints": "Endpoints", "where we fetch models": "where we fetch models", "All endpoints are OpenAI-compatible. Point the Base URL at OpenAI, OpenRouter, a local Ollama, or any self-hosted server.": "All endpoints are OpenAI-compatible. Point the Base URL at OpenAI, OpenRouter, a local Ollama, or any self-hosted server.", diff --git a/apps/client/src/components/ui/git-sync-badge.tsx b/apps/client/src/components/ui/git-sync-badge.tsx new file mode 100644 index 00000000..805d0d0e --- /dev/null +++ b/apps/client/src/components/ui/git-sync-badge.tsx @@ -0,0 +1,36 @@ +import { Badge, Tooltip } from "@mantine/core"; +import { IconGitMerge } from "@tabler/icons-react"; +import { useTranslation } from "react-i18next"; + +interface GitSyncBadgeProps { + authorName?: string; +} + +/** + * Badge marking a version written by the git-sync data plane โ€” a VaultGit pull + * applied through the native datasource (provenance ยง8.1). Like {@link AiAgentBadge} + * it is ADDITIVE โ€” shown next to the human author, never replacing them. A + * git-sync edit is NOT an agent edit and has no chat to deep-link into, so it is + * a small, neutral, non-clickable label. + */ +export function GitSyncBadge({ authorName }: GitSyncBadgeProps) { + const { t } = useTranslation(); + + const tooltip = t("Synced from Git on behalf of {{name}}", { + name: authorName ?? "", + }); + + return ( + + } + > + {t("Git sync")} + + + ); +} diff --git a/apps/client/src/features/page-history/components/history-item.tsx b/apps/client/src/features/page-history/components/history-item.tsx index ccb15c0a..9a6d25a5 100644 --- a/apps/client/src/features/page-history/components/history-item.tsx +++ b/apps/client/src/features/page-history/components/history-item.tsx @@ -1,6 +1,7 @@ import { Text, Group, UnstyledButton, Avatar, Tooltip } from "@mantine/core"; import { CustomAvatar } from "@/components/ui/custom-avatar.tsx"; import { AiAgentBadge } from "@/components/ui/ai-agent-badge.tsx"; +import { GitSyncBadge } from "@/components/ui/git-sync-badge.tsx"; import { formattedDate } from "@/lib/time"; import classes from "./css/history.module.css"; import clsx from "clsx"; @@ -41,6 +42,7 @@ const HistoryItem = memo(function HistoryItem({ const contributors = historyItem.contributors; const hasContributors = contributors && contributors.length > 0; const isAgentEdit = historyItem.lastUpdatedSource === "agent"; + const isGitSyncEdit = historyItem.lastUpdatedSource === "git-sync"; return ( setHistoryModalOpen(false)} /> )} + + {isGitSyncEdit && ( + + )} );