feat: ensureLocalGitRepo() — git init automatisch wenn kein eigenes Repo

Wenn ein Projekt-Verzeichnis kein eigenes .git hat aber in einem
übergeordneten Repo liegt (z.B. ~/Python_Programs/* im Home-Repo),
würde git add -A das gesamte Home-Verzeichnis scannen — inkl.
HuggingFace-Modelle und Podman-Overlays → Minuten-lange Hänger.

Lösung: ensureLocalGitRepo() prüft am Anfang aller Coding-Kommandos
(/coder, /optimize, /fix, /patch) ob ctx.cwd ein eigenes .git hat.
Falls nicht: git init + .gitignore + initialer Commit — mit Warnung.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Dieter Schlüter 2026-06-15 18:14:40 +02:00
commit 0cb637783c

View file

@ -897,6 +897,47 @@ async function runVersionBump(pi: ExtensionAPI, ctx: ExtensionCommandContext): P
ctx.ui.notify(`Version ${newTag} getaggt.`, "info"); ctx.ui.notify(`Version ${newTag} getaggt.`, "info");
} }
// Stellt sicher, dass ctx.cwd ein eigenes git-Repo hat (nicht nur ein übergeordnetes).
// Hintergrund: git add -A sucht das Repo-Root — bei Home-Verzeichnis-Repos würde das den
// gesamten Home-Baum indizieren (HuggingFace-Modelle, Podman-Overlays usw., 100k+ Dateien).
// Wird am Anfang aller Coding-Kommandos aufgerufen die git-Commits durchführen.
async function ensureLocalGitRepo(
pi: ExtensionAPI,
ctx: ExtensionCommandContext
): Promise<void> {
const localGit = await pi.exec("bash", ["-c", "test -d .git && echo yes"], { cwd: ctx.cwd });
if (localGit.stdout.trim() === "yes") return;
const root = await pi.exec("bash", ["-c", "git rev-parse --show-toplevel 2>/dev/null"], { cwd: ctx.cwd });
const repoRoot = root.stdout.trim();
if (repoRoot && repoRoot !== ctx.cwd) {
ctx.ui.notify(
`⚠ Kein lokales Git-Repo in ${ctx.cwd} (Git-Root war: ${repoRoot}) — git init wird ausgeführt.`,
"warning"
);
}
await pi.exec("bash", ["-c", "git init"], { cwd: ctx.cwd });
const gitignoreCheck = await pi.exec("bash", ["-c", "test -f .gitignore && echo exists"], { cwd: ctx.cwd });
if (gitignoreCheck.stdout.trim() !== "exists") {
const gitignore = [
"__pycache__/", "*.pyc", "*.pyo", ".venv/", "venv/",
"target/", "*.o", "*.d",
"node_modules/", "dist/", "build/", "*.egg-info/",
".env", ".DS_Store", "*.swp",
].join("\n") + "\n";
await pi.exec("bash", ["-c", 'printf "%s" "$1" > .gitignore', "_", gitignore], { cwd: ctx.cwd });
}
await pi.exec(
"bash",
["-c", "git add . && git commit -m 'chore: init project' || true"],
{ cwd: ctx.cwd }
);
ctx.ui.notify(`Git-Repo initialisiert: ${ctx.cwd}`, "info");
}
// Committed alle ungespeicherten Änderungen nach SHIP — Sicherheitsnetz falls der LLM es vergessen hat. // Committed alle ungespeicherten Änderungen nach SHIP — Sicherheitsnetz falls der LLM es vergessen hat.
async function autoCommitIfDirty(pi: ExtensionAPI, ctx: ExtensionCommandContext): Promise<void> { async function autoCommitIfDirty(pi: ExtensionAPI, ctx: ExtensionCommandContext): Promise<void> {
const status = await pi.exec("bash", ["-c", "git status --porcelain"], { cwd: ctx.cwd }); const status = await pi.exec("bash", ["-c", "git status --porcelain"], { cwd: ctx.cwd });
@ -1098,6 +1139,7 @@ export default function (pi: ExtensionAPI) {
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error"); ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
return; return;
} }
await ensureLocalGitRepo(pi, ctx);
await writeTaskMd(pi, ctx, task); await writeTaskMd(pi, ctx, task);
await selectRole(pi, ctx, "coder"); await selectRole(pi, ctx, "coder");
currentActivity = "Coder implementiert…"; currentActivity = "Coder implementiert…";
@ -1127,6 +1169,7 @@ export default function (pi: ExtensionAPI) {
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error"); ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
return; return;
} }
await ensureLocalGitRepo(pi, ctx);
await selectRole(pi, ctx, "coder"); await selectRole(pi, ctx, "coder");
currentActivity = "Coder fixt Judge-Kritik…"; currentActivity = "Coder fixt Judge-Kritik…";
await sendAndWait(pi, ctx, fixPrompt(args || "")); await sendAndWait(pi, ctx, fixPrompt(args || ""));
@ -1191,6 +1234,8 @@ export default function (pi: ExtensionAPI) {
} }
try { try {
await ensureLocalGitRepo(pi, ctx);
if (continueMode) { if (continueMode) {
// --continue: Implementierungsphase überspringen, direkt in Judge→Fix-Schleife // --continue: Implementierungsphase überspringen, direkt in Judge→Fix-Schleife
// Erweiterter Auftrag wird als Zusatzauftrag in TASK.md eingetragen (falls angegeben) // Erweiterter Auftrag wird als Zusatzauftrag in TASK.md eingetragen (falls angegeben)
@ -1437,6 +1482,7 @@ export default function (pi: ExtensionAPI) {
ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error"); ctx.ui.notify("Server nicht bereit (Port 8001) — start-coding-server.sh ausführen", "error");
return; return;
} }
await ensureLocalGitRepo(pi, ctx);
await selectRole(pi, ctx, "coder"); await selectRole(pi, ctx, "coder");
currentActivity = "Coder patcht…"; currentActivity = "Coder patcht…";
await sendAndWait(pi, ctx, patchPrompt(change)); await sendAndWait(pi, ctx, patchPrompt(change));