Lucy-Pipeline (S3): Auftragsbuch liest zwei Repos, Annahme baut am PC
Das Auftragsbuch-Gegenstueck fuer Lucy (Abloesungs-Paket S3, PC-Annahme-Weg): - backend/services/auftragsbuch.py: Multi-Repo (mc2 + lucy via ~/lucy-Clone). Karten tragen repo-Feld; Status-Schluessel fuer Lucy = 'lucy:<branch>'; fehlt ~/lucy, werden Lucy-Karten still weggelassen. Runner je Repo. - deploy/lucy-annahme.sh: detached Annahme-Runner fuer Lucy-Karten. Vorpruefung am PC VOR dem Merge (Executor erreichbar, Arbeitskopie main+clean, laeuft Lucy?), dann Merge im isolierten Worktree von ~/lucy -> Push main -> PC zieht ff-only und baut detached (deploy/lucy-annahme.ps1 im Lucy-Repo), Box pollt .lucy-annahme.json und spiegelt Fortschritt auf die Karte. Rot = Merge automatisch revertiert, laufende Lucy bleibt die alte. Executor-Zugang (URL+Token) kommt aus ~/.hermes/config.yaml — kein zweiter Ablageort. Neustart nur, wenn Lucy vorher lief (User-Entscheid). - Router/UI: repo-Parameter (rueckwaertskompatibel, Default mc2), rosa Lucy-Badge, eigener Annahme-Confirm-Text, Diff/Ablehnen je Repo. - werkstatt-SOUL: Lucy-Auftraege ebenfalls propose-only, bauen macht der PC bei der Annahme. - Doku: docs/AUFTRAGSBUCH.md (Lucy-Annahme-Kapitel), docs/wissen/OFFENE-FAEDEN (S2 erledigt, S3-Stand). Geprueft: py_compile gruen, bash -n gruen, tsc+vite build gruen (dist dabei).
This commit is contained in:
@@ -104,7 +104,7 @@ export function AuftragsbuchView() {
|
||||
<section className="space-y-3">
|
||||
<SectionLabel icon={GitBranch}>Fertige Patches ({items.length})</SectionLabel>
|
||||
{items.map((it) => (
|
||||
<ProposalCard key={it.branch} item={it} busy={busy} onAct={act} showConfirm={showConfirm} />
|
||||
<ProposalCard key={`${it.repo ?? "mc2"}:${it.branch}`} item={it} busy={busy} onAct={act} showConfirm={showConfirm} />
|
||||
))}
|
||||
</section>
|
||||
)}
|
||||
@@ -285,6 +285,10 @@ function ProposalCard({
|
||||
const [diffLoading, setDiffLoading] = useState(false)
|
||||
const running = item.status?.state === "laeuft" || item.status?.state === "rollback"
|
||||
const decided = item.status?.state === "eingespielt"
|
||||
// Lucy-Karten (Desktop-App): Annehmen baut am PC (dist) statt auf der Box zu deployen.
|
||||
const repo = item.repo ?? "mc2"
|
||||
const isLucy = repo === "lucy"
|
||||
const k = `${repo}:${item.branch}`
|
||||
|
||||
async function loadDiff() {
|
||||
const next = !open
|
||||
@@ -292,7 +296,7 @@ function ProposalCard({
|
||||
if (next && diff === null) {
|
||||
setDiffLoading(true)
|
||||
try {
|
||||
const r = await api<{ diff: string; truncated: boolean }>(`/api/auftragsbuch/diff?branch=${encodeURIComponent(item.branch)}`)
|
||||
const r = await api<{ diff: string; truncated: boolean }>(`/api/auftragsbuch/diff?branch=${encodeURIComponent(item.branch)}&repo=${repo}`)
|
||||
setDiff(r.diff + (r.truncated ? "\n… (gekürzt)" : ""))
|
||||
} catch (e: any) {
|
||||
setDiff(`(Diff nicht ladbar: ${e?.message || e})`)
|
||||
@@ -310,6 +314,12 @@ function ProposalCard({
|
||||
<span className="rounded-md border border-primary/30 bg-primary/10 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-primary">
|
||||
{KIND_LABEL[item.kind] ?? item.kind}
|
||||
</span>
|
||||
{isLucy && (
|
||||
<span className="rounded-md border border-pink-500/40 bg-pink-500/10 px-1.5 py-0.5 text-[10px] font-bold uppercase tracking-wider text-pink-300"
|
||||
title="Vorschlag fürs Lucy-Repo — Annehmen baut die App am PC neu und startet sie neu, wenn sie läuft.">
|
||||
Lucy
|
||||
</span>
|
||||
)}
|
||||
<span className="font-mono text-[11px] text-muted-foreground truncate" title={item.branch}>{item.branch}</span>
|
||||
<span className="flex items-center gap-1 text-[10px] text-muted-foreground/70"><Clock className="h-3 w-3" />{fmtWhen(item.ts)}</span>
|
||||
<StateBadge item={item} />
|
||||
@@ -321,22 +331,24 @@ function ProposalCard({
|
||||
{!running && !decided && (
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
<button
|
||||
disabled={!!busy[item.branch]}
|
||||
disabled={!!busy[k]}
|
||||
onClick={() =>
|
||||
showConfirm("Vorschlag annehmen?",
|
||||
`'${item.branch}' wird auf main gemergt und live eingespielt. Die Zentrale startet dabei kurz neu. Geht der Health-Check danach rot, rollt die Box automatisch zurück.${item.frontend_ohne_build ? "\n\nAchtung: Enthält Frontend-Quelltext ohne gebautes Bundle — die Oberfläche bleibt alt, bis am PC gebaut wird." : ""}`,
|
||||
() => onAct(item.branch, "/api/auftragsbuch/annehmen", { branch: item.branch }))}
|
||||
isLucy
|
||||
? `'${item.branch}' wird im Lucy-Repo auf main gemergt, dann baut dein PC die App neu (dist) und startet Lucy neu, falls sie gerade läuft. Der PC muss dafür an sein. Schlägt Build oder Start fehl, dreht die Box den Merge automatisch zurück — die laufende Lucy bleibt die alte.`
|
||||
: `'${item.branch}' wird auf main gemergt und live eingespielt. Die Zentrale startet dabei kurz neu. Geht der Health-Check danach rot, rollt die Box automatisch zurück.${item.frontend_ohne_build ? "\n\nAchtung: Enthält Frontend-Quelltext ohne gebautes Bundle — die Oberfläche bleibt alt, bis am PC gebaut wird." : ""}`,
|
||||
() => onAct(k, "/api/auftragsbuch/annehmen", { branch: item.branch, repo }))}
|
||||
className="flex h-9 items-center gap-1.5 rounded-lg border border-emerald-500/40 bg-emerald-500/10 px-3 text-[11px] font-bold uppercase tracking-wide text-emerald-300 transition-all hover:bg-emerald-500/20 cursor-pointer disabled:opacity-50">
|
||||
{busy[item.branch] ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Check className="h-3.5 w-3.5" />} Annehmen
|
||||
{busy[k] ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Check className="h-3.5 w-3.5" />} Annehmen
|
||||
</button>
|
||||
<button
|
||||
disabled={!!busy["ab:" + item.branch]}
|
||||
disabled={!!busy["ab:" + k]}
|
||||
onClick={() =>
|
||||
showConfirm("Vorschlag ablehnen?",
|
||||
`Der Branch '${item.branch}' wird auf Gitea gelöscht. Die Arbeit bleibt in der Historie, aber die Karte verschwindet.`,
|
||||
() => onAct("ab:" + item.branch, "/api/auftragsbuch/ablehnen", { branch: item.branch }))}
|
||||
() => onAct("ab:" + k, "/api/auftragsbuch/ablehnen", { branch: item.branch, repo }))}
|
||||
className="flex h-9 items-center gap-1.5 rounded-lg border border-red-500/30 bg-red-500/5 px-3 text-[11px] font-bold uppercase tracking-wide text-red-300/90 transition-all hover:bg-red-500/15 cursor-pointer disabled:opacity-50">
|
||||
{busy["ab:" + item.branch] ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <X className="h-3.5 w-3.5" />} Ablehnen
|
||||
{busy["ab:" + k] ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <X className="h-3.5 w-3.5" />} Ablehnen
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user