diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..93fbf69 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,11 @@ +{ + "permissions": { + "allow": [ + "WebFetch(domain:antigravity.google)", + "Bash(get-childitem:*)", + "WebFetch(domain:geminicli.com)", + "WebFetch(domain:google-gemini.github.io)", + "Bash(Get-ChildItem \"C:\\\\work\\\\claude-meta\\\\home-claude\")" + ] + } +} diff --git a/docs/FRAMEWORK.md b/docs/FRAMEWORK.md index a5dd98e..c0460f7 100644 --- a/docs/FRAMEWORK.md +++ b/docs/FRAMEWORK.md @@ -100,9 +100,57 @@ cd ~/work/claude-meta Junctions brauchen kein Admin/Developer Mode, funktionieren aber nur auf gleichem Volume. +## Gemini CLI & Antigravity Integration + +Beide Tools nutzen `~/.gemini/GEMINI.md` als globale Anweisungsdatei (analog zu CLAUDE.md). `home-claude/rules/` ist die gemeinsame Source of Truth. + +### Struktur nach install.ps1 / install.sh + +``` +~/.gemini/ + GEMINI.md ← COPY von home-gemini/GEMINI.md (kein Symlink, s.u.) + settings.json ← COPY von home-gemini/settings.json (kein Symlink, s.u.) + rules/ → Junction/Symlink → home-claude/rules/ (geteilt mit Claude) + skills/ + review/ → Junction/Symlink → home-claude/skills/review/ + plan-project/ → Junction/Symlink → home-claude/skills/plan-project/ +``` + +### Was bei welchem Tool ankommt + +| | Gemini CLI | Antigravity IDE | +|---|---|---| +| Verhaltensregeln (GEMINI.md) | ✓ | ✓ | +| @rules/* (code-style, dotnet, git) | ✓ | ✓ | +| memory/ (includeDirectories) | ✓ | ✗ (nicht unterstützt) | +| Skills (review, plan-project) | ✓ | ✗ (s. Hinweis unten) | + +### Warum kein Symlink für GEMINI.md und settings.json + +**GEMINI.md:** Gemini CLI verweigert Symlinks aus Sicherheitsgründen (Issue #11547, closed "not planned"). + +**settings.json:** Gemini CLI überschreibt den Symlink bei jedem automatischen Settings-Update mit einer echten Datei — der Link wird still zerstört (Issue #10960, closed "not planned"). Daher wird auch settings.json immer kopiert. Nach Änderungen an `home-gemini/settings.json` muss `install.ps1` erneut ausgeführt werden. + +### Antigravity Skills (TODO) + +Antigravity nutzt `~/.gemini/antigravity/skills/` statt `~/.gemini/skills/`. Die Skills aus `home-claude/skills/` sind für Antigravity daher aktuell **nicht** sichtbar. `install.ps1` und `install.sh` könnten um einen Block erweitert werden, der Junctions/Symlinks nach `~/.gemini/antigravity/skills/review/` und `~/.gemini/antigravity/skills/plan-project/` anlegt. + +### Regeln nach Änderungen aktualisieren + +Regeländerungen in `home-claude/rules/` wirken sofort (Junction/Symlink). Für GEMINI.md und settings.json gilt: + +```powershell +.\scripts\install.ps1 # kopiert GEMINI.md und settings.json neu +``` + +Achtung: Antigravity überschreibt `~/.gemini/GEMINI.md` wenn der User über "+ Global" Regeln hinzufügt. In dem Fall `install.ps1` erneut ausführen. + ## Bekannte Einschränkungen - Claude Code Issue #764: Symlink auf ~/.claude/ Verzeichnis → Dateien unsichtbar - Junctions nur auf gleichem Volume (C: → C:) - @imports haben max 5 Rekursionstiefe - Erste @import-Nutzung braucht einmalige Bestätigung pro Projekt +- Gemini CLI Issue #11547: GEMINI.md darf kein Symlink sein +- Gemini CLI Issue #10960: settings.json-Symlink wird bei CLI-Updates zerstört +- Antigravity und Gemini CLI teilen ~/.gemini/GEMINI.md — Antigravity kann die Datei überschreiben diff --git a/home-gemini/GEMINI.md b/home-gemini/GEMINI.md new file mode 100644 index 0000000..2f5fe92 --- /dev/null +++ b/home-gemini/GEMINI.md @@ -0,0 +1,5 @@ +Sei extrem prägnant. Opfere Grammatik für Kürze. +Kommentare und Commit-Messages in Englisch. +Am Ende jeder Planung: Liste offener Fragen (kurz). + +Regeln: @rules/code-style.md @rules/dotnet.md @rules/git.md diff --git a/home-gemini/settings.json b/home-gemini/settings.json new file mode 100644 index 0000000..45ffa68 --- /dev/null +++ b/home-gemini/settings.json @@ -0,0 +1,6 @@ +{ + "model": { "name": "gemini-2.5-pro" }, + "context": { + "includeDirectories": ["C:/work/claude-meta/memory"] + } +} diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 50d875e..2d00258 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -112,6 +112,125 @@ foreach ($dir in $dirs) { } } +# ============================================================ +# GEMINI INSTALL +# ============================================================ +$geminiSourceDir = Join-Path $repoRoot "home-gemini" +$geminiDir = Join-Path $env:USERPROFILE ".gemini" +$claudeRulesDir = Join-Path $sourceDir "rules" + +Write-Host "" +Write-Host "Installing Gemini config..." -ForegroundColor Cyan +Write-Host " Source: $geminiSourceDir" -ForegroundColor Gray +Write-Host " Target: $geminiDir" -ForegroundColor Gray +Write-Host "" + +if (-not (Test-Path $geminiSourceDir)) { + Write-Host " SKIP: home-gemini/ not found" -ForegroundColor Yellow +} else { + # Ensure ~/.gemini/ is a real directory + if (Test-Path $geminiDir) { + $item = Get-Item $geminiDir -Force + if ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) { + Write-Host " ERROR: ~/.gemini/ is a symlink/junction. Must be a real directory." -ForegroundColor Red + $success = $false + } + } else { + New-Item -ItemType Directory -Path $geminiDir -Force | Out-Null + Write-Host " Created ~/.gemini/" -ForegroundColor Cyan + } + + # Check same volume for junctions + $geminiVolume = (Get-Item $geminiDir).PSDrive.Name + $geminiUseJunctions = ($sourceVolume -eq $geminiVolume) + + # GEMINI.md — always copy (no symlink, Gemini CLI issue #11547) + $geminiMdSrc = Join-Path $geminiSourceDir "GEMINI.md" + $geminiMdDst = Join-Path $geminiDir "GEMINI.md" + if (Test-Path $geminiMdSrc) { + Copy-Item $geminiMdSrc $geminiMdDst -Force + Write-Host " COPY: GEMINI.md (symlinks not supported by Gemini CLI)" -ForegroundColor Green + } + + # settings.json — try symlink, fallback to copy + $settingsSrc = Join-Path $geminiSourceDir "settings.json" + $settingsDst = Join-Path $geminiDir "settings.json" + if (Test-Path $settingsSrc) { + if (Test-Path $settingsDst) { Remove-Item $settingsDst -Force } + try { + New-Item -ItemType SymbolicLink -Path $settingsDst -Target $settingsSrc -ErrorAction Stop | Out-Null + Write-Host " SYMLINK: settings.json -> $settingsSrc" -ForegroundColor Green + } catch { + Copy-Item $settingsSrc $settingsDst -Force + Write-Host " COPY: settings.json (symlink failed)" -ForegroundColor Yellow + $success = $false + } + } + + # rules/ — junction to home-claude/rules/ (shared source of truth) + $geminiRulesDst = Join-Path $geminiDir "rules" + if (Test-Path $claudeRulesDir) { + if (Test-Path $geminiRulesDst) { + $item = Get-Item $geminiRulesDst -Force + if ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) { + cmd /c "rmdir `"$geminiRulesDst`"" 2>$null + } else { + Remove-Item $geminiRulesDst -Recurse -Force + } + } + if ($geminiUseJunctions) { + cmd /c "mklink /J `"$geminiRulesDst`" `"$claudeRulesDir`"" | Out-Null + if ($LASTEXITCODE -eq 0) { + Write-Host " JUNCTION: rules/ -> $claudeRulesDir" -ForegroundColor Green + } else { + Copy-Item $claudeRulesDir $geminiRulesDst -Recurse -Force + Write-Host " COPY: rules/ (junction failed)" -ForegroundColor Yellow + $success = $false + } + } else { + Copy-Item $claudeRulesDir $geminiRulesDst -Recurse -Force + Write-Host " COPY: rules/ (different volume)" -ForegroundColor Yellow + $success = $false + } + } + + # skills/ — selective junctions for review/ and plan-project/ + $geminiSkillsDir = Join-Path $geminiDir "skills" + if (-not (Test-Path $geminiSkillsDir)) { + New-Item -ItemType Directory -Path $geminiSkillsDir -Force | Out-Null + } + foreach ($skill in @("review", "plan-project")) { + $skillSrc = Join-Path $sourceDir "skills\$skill" + $skillDst = Join-Path $geminiSkillsDir $skill + if (-not (Test-Path $skillSrc)) { + Write-Host " SKIP: skills/$skill/ (not in repo)" -ForegroundColor Yellow + continue + } + if (Test-Path $skillDst) { + $item = Get-Item $skillDst -Force + if ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) { + cmd /c "rmdir `"$skillDst`"" 2>$null + } else { + Remove-Item $skillDst -Recurse -Force + } + } + if ($geminiUseJunctions) { + cmd /c "mklink /J `"$skillDst`" `"$skillSrc`"" | Out-Null + if ($LASTEXITCODE -eq 0) { + Write-Host " JUNCTION: skills/$skill/ -> $skillSrc" -ForegroundColor Green + } else { + Copy-Item $skillSrc $skillDst -Recurse -Force + Write-Host " COPY: skills/$skill/ (junction failed)" -ForegroundColor Yellow + $success = $false + } + } else { + Copy-Item $skillSrc $skillDst -Recurse -Force + Write-Host " COPY: skills/$skill/ (different volume)" -ForegroundColor Yellow + $success = $false + } + } +} + # --- Validation --- Write-Host "" Write-Host "Validating..." -ForegroundColor Cyan @@ -144,6 +263,31 @@ foreach ($dir in $dirs) { } } +# Gemini validation +if (Test-Path $geminiSourceDir) { + $geminiMdDst = Join-Path $geminiDir "GEMINI.md" + if (Test-Path $geminiMdDst) { + $item = Get-Item $geminiMdDst -Force + if ($item.Attributes -band [System.IO.FileAttributes]::ReparsePoint) { + Write-Host " FAIL: ~/.gemini/GEMINI.md is a symlink (Gemini CLI rejects this!)" -ForegroundColor Red + $valid = $false + } else { + Write-Host " OK: ~/.gemini/GEMINI.md (real file)" -ForegroundColor Green + } + } else { + Write-Host " FAIL: ~/.gemini/GEMINI.md not found" -ForegroundColor Red + $valid = $false + } + $geminiRulesDst = Join-Path $geminiDir "rules" + if (Test-Path $geminiRulesDst) { + $count = (Get-ChildItem $geminiRulesDst -Recurse -File).Count + Write-Host " OK: ~/.gemini/rules/ ($count files)" -ForegroundColor Green + } else { + Write-Host " FAIL: ~/.gemini/rules/ not found" -ForegroundColor Red + $valid = $false + } +} + # --- Summary --- Write-Host "" if ($valid) { diff --git a/scripts/install.sh b/scripts/install.sh index f0af295..1c00f74 100644 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -82,5 +82,84 @@ for dir in skills rules commands; do fi done +echo "" +echo "Installing Gemini config..." + +GEMINI_SOURCE_DIR="$REPO_ROOT/home-gemini" +GEMINI_DIR="$HOME/.gemini" +CLAUDE_RULES_DIR="$SOURCE_DIR/rules" + +if [ ! -d "$GEMINI_SOURCE_DIR" ]; then + echo " SKIP: home-gemini/ not found" +else + echo " Source: $GEMINI_SOURCE_DIR" + echo " Target: $GEMINI_DIR" + echo "" + + # Ensure ~/.gemini/ is a real directory + if [ -L "$GEMINI_DIR" ]; then + echo " ERROR: ~/.gemini/ is a symlink. Must be a real directory." + exit 1 + fi + mkdir -p "$GEMINI_DIR" + + # GEMINI.md — always copy (no symlink, Gemini CLI issue #11547) + src="$GEMINI_SOURCE_DIR/GEMINI.md" + dst="$GEMINI_DIR/GEMINI.md" + if [ -f "$src" ]; then + cp -f "$src" "$dst" + echo " COPY: GEMINI.md (symlinks not supported by Gemini CLI)" + fi + + # settings.json — symlink + src="$GEMINI_SOURCE_DIR/settings.json" + dst="$GEMINI_DIR/settings.json" + if [ -f "$src" ]; then + [ -e "$dst" ] || [ -L "$dst" ] && rm -f "$dst" + ln -s "$src" "$dst" + echo " SYMLINK: settings.json -> $src" + fi + + # rules/ — symlink to home-claude/rules/ (shared source of truth) + dst="$GEMINI_DIR/rules" + if [ -d "$CLAUDE_RULES_DIR" ]; then + [ -L "$dst" ] && rm "$dst" || { [ -d "$dst" ] && rm -rf "$dst"; } + ln -s "$CLAUDE_RULES_DIR" "$dst" + echo " SYMLINK: rules/ -> $CLAUDE_RULES_DIR" + fi + + # skills/ — selective symlinks for review/ and plan-project/ + mkdir -p "$GEMINI_DIR/skills" + for skill in review plan-project; do + skill_src="$SOURCE_DIR/skills/$skill" + skill_dst="$GEMINI_DIR/skills/$skill" + if [ ! -d "$skill_src" ]; then + echo " SKIP: skills/$skill/ (not in repo)" + continue + fi + [ -L "$skill_dst" ] && rm "$skill_dst" || { [ -d "$skill_dst" ] && rm -rf "$skill_dst"; } + ln -s "$skill_src" "$skill_dst" + echo " SYMLINK: skills/$skill/ -> $skill_src" + done + + echo "" + echo "Validating Gemini..." + dst="$GEMINI_DIR/GEMINI.md" + if [ -f "$dst" ] && [ ! -L "$dst" ] && [ -s "$dst" ]; then + echo " OK: ~/.gemini/GEMINI.md (real file)" + elif [ -L "$dst" ]; then + echo " FAIL: ~/.gemini/GEMINI.md is a symlink (Gemini CLI rejects this!)" + else + echo " FAIL: ~/.gemini/GEMINI.md" + fi + dst="$GEMINI_DIR/rules" + if [ -d "$dst" ]; then + count=$(find "$dst" -type f | wc -l) + echo " OK: ~/.gemini/rules/ ($count files)" + else + echo " FAIL: ~/.gemini/rules/" + fi +fi + echo "" echo "Installation complete!"