feat(git-sync): client 'Git sync' provenance badge + git in runtime image (Phase D)

- 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 <noreply@anthropic.com>
This commit is contained in:
claude code agent 227
2026-06-21 15:50:15 +03:00
parent 0a364dfcac
commit 772ddb9582
3 changed files with 38 additions and 2 deletions

View File

@@ -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

View File

@@ -1172,6 +1172,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.",

View File

@@ -1,5 +1,5 @@
import { Text, Group, UnstyledButton, Avatar, Tooltip, Badge } from "@mantine/core";
import { IconSparkles } from "@tabler/icons-react";
import { IconSparkles, IconGitMerge } from "@tabler/icons-react";
import { CustomAvatar } from "@/components/ui/custom-avatar.tsx";
import { formattedDate } from "@/lib/time";
import classes from "./css/history.module.css";
@@ -107,6 +107,34 @@ function AiAgentBadge({
);
}
/**
* Badge marking a version written by the git-sync VaultGit pull (provenance §8.1).
* Like {@link AiAgentBadge} it is ADDITIVE — shown next to the human author —
* but a git-sync edit is NOT an agent edit, so it is rendered as a small, neutral
* badge with NO deep-link (there is no AI chat behind it).
*/
function GitSyncBadge({ authorName }: { authorName?: string }) {
const { t } = useTranslation();
const tooltip = t("Synced from Git on behalf of {{name}}", {
name: authorName ?? "",
});
return (
<Tooltip label={tooltip} withArrow>
<Badge
size="sm"
variant="light"
color="gray"
radius="sm"
leftSection={<IconGitMerge size={12} stroke={2} />}
>
{t("Git sync")}
</Badge>
</Tooltip>
);
}
const HistoryItem = memo(function HistoryItem({
historyItem,
index,
@@ -126,6 +154,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 (
<UnstyledButton
@@ -190,6 +219,10 @@ const HistoryItem = memo(function HistoryItem({
aiChatId={historyItem.lastUpdatedAiChatId}
/>
)}
{isGitSyncEdit && (
<GitSyncBadge authorName={historyItem.lastUpdatedBy?.name} />
)}
</Group>
</UnstyledButton>
);