fix(bootstrap): cover both python interpreters + grok PATH + git auth
Amend windows-bootstrap.ps1 with every gap the 2026-06-06 GURU-5070 reinstall exposed, so the next rebuild is clean: - Phase 7: install python deps into BOTH interpreters (py/3.14 for vault + scripts, python/3.12 for the MCP servers). Single-interpreter installs left ticktick MCP (no httpx/mcp in 3.12) and vault get-field (no PyYAML in 3.14) dead. Add pyyaml + websocket-client to the baseline libs. - Phase 3: persist ~\.grok\bin (+ ~\.local\bin, %APPDATA%\npm) to the User PATH; grok's installer leaves it session-only. - Phase 6: prime non-interactive git auth (setup-git-auth.sh) so pushes never hang on a GCM prompt. - Phase 8: expand to the real 5-model set and add the hydration gotcha so a populated D:\OllamaModels is never needlessly re-downloaded (~48 GB). Document all four in machines/guru-5070.md known issues. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -149,6 +149,15 @@ if (Phase 3 'AI CLIs') {
|
|||||||
}
|
}
|
||||||
Refresh-Path
|
Refresh-Path
|
||||||
$env:Path += ";$env:USERPROFILE\.local\bin;$env:USERPROFILE\.grok\bin;$env:APPDATA\npm"
|
$env:Path += ";$env:USERPROFILE\.local\bin;$env:USERPROFILE\.grok\bin;$env:APPDATA\npm"
|
||||||
|
# Persist the AI-CLI dirs to the User PATH so claude/grok/gemini stay callable in
|
||||||
|
# every new shell (their installers don't always add these; grok especially is a
|
||||||
|
# bare ~\.grok\bin drop that was session-only after the 2026-06-06 rebuild).
|
||||||
|
$userPath = [Environment]::GetEnvironmentVariable('Path','User')
|
||||||
|
foreach ($d in "$env:USERPROFILE\.local\bin", "$env:USERPROFILE\.grok\bin", "$env:APPDATA\npm") {
|
||||||
|
if ((Test-Path $d) -and ($userPath -notmatch [regex]::Escape($d))) { $userPath = $userPath.TrimEnd(';') + ";$d" }
|
||||||
|
}
|
||||||
|
[Environment]::SetEnvironmentVariable('Path', $userPath, 'User')
|
||||||
|
Ok "AI-CLI dirs persisted to User PATH"
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================ PHASE 4
|
# ============================================================ PHASE 4
|
||||||
@@ -209,6 +218,19 @@ if (Phase 6 'Restore repo-local identity + at-risk WIP') {
|
|||||||
& "$here\restore-at-risk-work.ps1" -BundlePath $script:Bundle -ClaudeToolsRoot $ClaudeToolsRoot
|
& "$here\restore-at-risk-work.ps1" -BundlePath $script:Bundle -ClaudeToolsRoot $ClaudeToolsRoot
|
||||||
}
|
}
|
||||||
else { Warn "no bundle - you must hand-create .claude/identity.json (see CLAUDE.md multi-user section)" }
|
else { Warn "no bundle - you must hand-create .claude/identity.json (see CLAUDE.md multi-user section)" }
|
||||||
|
|
||||||
|
# Non-interactive git auth (Mike's hard requirement: git must NEVER hang on a
|
||||||
|
# Git Credential Manager password prompt). setup-git-auth.sh primes the `store`
|
||||||
|
# credential helper from the vault Gitea token, scoped to each repo's actual remote
|
||||||
|
# host. Needs the age key (Phase 4) + identity.json (above) + vault repo (Phase 5).
|
||||||
|
# Idempotent + fail-silent; also runs from the SessionStart hook in settings.json.
|
||||||
|
$ghauth = "$ClaudeToolsRoot\.claude\scripts\setup-git-auth.sh"
|
||||||
|
$gbash = 'C:\Program Files\Git\bin\bash.exe'
|
||||||
|
if ((Test-Path $ghauth) -and (Test-Path $gbash)) {
|
||||||
|
Info "priming non-interactive git auth (vault token -> credential store)"
|
||||||
|
& $gbash "$ghauth"
|
||||||
|
Ok "git credential store primed; GIT_TERMINAL_PROMPT=0 enforced via .claude/settings.json env"
|
||||||
|
} else { Warn "setup-git-auth.sh or Git Bash missing - prime git creds manually so pushes don't prompt" }
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================ PHASE 7
|
# ============================================================ PHASE 7
|
||||||
@@ -218,30 +240,61 @@ if (Phase 7 'Python deps + .NET tools') {
|
|||||||
if (dotnet tool list --global 2>$null | Select-String '\bwix\b') { Ok "wix tool already installed" }
|
if (dotnet tool list --global 2>$null | Select-String '\bwix\b') { Ok "wix tool already installed" }
|
||||||
else { Info "installing wix dotnet tool"; dotnet tool install --global wix 2>$null }
|
else { Info "installing wix dotnet tool"; dotnet tool install --global wix 2>$null }
|
||||||
}
|
}
|
||||||
if (Have py) {
|
# IMPORTANT: ClaudeTools uses TWO python interpreters on Windows and they must
|
||||||
py -m pip install --upgrade pip 2>$null
|
# BOTH have the deps, or pieces silently break:
|
||||||
|
# - `py` -> Python 3.14 : vault yaml-query.py (get-field), helper/skill
|
||||||
|
# scripts, scheduled tasks (detect_orphaned_sessions)
|
||||||
|
# - `python` -> Python 3.12 : the interpreter `.mcp.json` launches the MCP
|
||||||
|
# servers with (ticktick needs httpx + mcp)
|
||||||
|
# Installing into only one leaves the other broken (the 2026-06-06 rebuild shipped
|
||||||
|
# with ticktick MCP dead = no httpx/mcp in 3.12, and vault get-field dead = no
|
||||||
|
# PyYAML in 3.14). De-dupe by real sys.executable so a single install isn't run twice.
|
||||||
|
$interps = @(); $seen = @{}
|
||||||
|
foreach ($cand in 'py','python','python3') {
|
||||||
|
if (Have $cand) {
|
||||||
|
$real = (& $cand -c "import sys;print(sys.executable)" 2>$null)
|
||||||
|
if ($real -and -not $seen[$real]) { $seen[$real] = $true; $interps += $cand }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (-not $interps) { Warn "no python interpreter found - skip python deps" }
|
||||||
|
else {
|
||||||
$reqs = Get-ChildItem $ClaudeToolsRoot -Recurse -Filter 'requirements*.txt' -ErrorAction SilentlyContinue |
|
$reqs = Get-ChildItem $ClaudeToolsRoot -Recurse -Filter 'requirements*.txt' -ErrorAction SilentlyContinue |
|
||||||
Where-Object { $_.FullName -notmatch '\\(node_modules|\.venv|venv|target)\\' }
|
Where-Object { $_.FullName -notmatch '\\(node_modules|\.venv|venv|target)\\' }
|
||||||
foreach ($r in $reqs) { Info "pip install -r $($r.FullName)"; py -m pip install -r $r.FullName 2>$null }
|
# baseline libs used by helper scripts / MCP / vault across the harness
|
||||||
# baseline libs used by helper scripts / MCP
|
$baseline = @('requests','paramiko','mcp','httpx','pyyaml','websocket-client')
|
||||||
py -m pip install requests paramiko mcp 2>$null
|
foreach ($ic in $interps) {
|
||||||
Ok "python deps installed (best-effort)"
|
Info "[$ic] upgrading pip"; & $ic -m pip install --upgrade pip 2>$null
|
||||||
} else { Warn "py launcher missing - skip" }
|
foreach ($r in $reqs) { Info "[$ic] pip install -r $($r.Name)"; & $ic -m pip install -r $r.FullName 2>$null }
|
||||||
|
Info "[$ic] baseline libs"; & $ic -m pip install @baseline 2>$null
|
||||||
|
}
|
||||||
|
Ok "python deps installed into: $($interps -join ', ') (best-effort)"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# ============================================================ PHASE 8
|
# ============================================================ PHASE 8
|
||||||
if (Phase 8 'Ollama models') {
|
if (Phase 8 'Ollama models') {
|
||||||
# Proper model set for THIS machine (Legion Pro 7, RTX 5070 Ti = 12 GB VRAM):
|
# Expected model set for THIS machine (identity.json prose_model + OLLAMA.md routing):
|
||||||
# nomic-embed-text - REQUIRED for GrepAI semantic search (embeddings)
|
# nomic-embed-text - REQUIRED for GrepAI semantic search (embeddings)
|
||||||
# qwen3:8b - configured prose_model (identity.json)
|
# qwen3:8b - prose_model qwen3:14b - heavier prose
|
||||||
# The heavier models (qwen3:14b 9GB, codestral:22b 12GB, qwen3.6:latest 23GB)
|
# codestral:22b - code suggestions qwen3.6:latest - structured/JSON + classify
|
||||||
# over-saturate 12 GB VRAM on a laptop. Pull them by hand only if needed:
|
# All five live on D:\OllamaModels (~48 GB) and SURVIVE an OS reset when D: is intact,
|
||||||
# ollama pull qwen3:14b # codestral:22b # qwen3.6:latest
|
# so a normal rebuild pulls NOTHING. Only a wiped D: triggers the full re-download.
|
||||||
$models = @('nomic-embed-text:latest','qwen3:8b')
|
$models = @('nomic-embed-text:latest','qwen3:8b','qwen3:14b','codestral:22b','qwen3.6:latest')
|
||||||
if ($SkipModels) { Warn "-SkipModels set, skipping model pulls" }
|
if ($SkipModels) { Warn "-SkipModels set, skipping model pulls" }
|
||||||
elseif (Have ollama) {
|
elseif (Have ollama) {
|
||||||
# Models live on D:\OllamaModels. If D: survived the reset they are already here.
|
|
||||||
if (-not $env:OLLAMA_MODELS) { [Environment]::SetEnvironmentVariable('OLLAMA_MODELS','D:\OllamaModels','User'); $env:OLLAMA_MODELS='D:\OllamaModels' }
|
if (-not $env:OLLAMA_MODELS) { [Environment]::SetEnvironmentVariable('OLLAMA_MODELS','D:\OllamaModels','User'); $env:OLLAMA_MODELS='D:\OllamaModels' }
|
||||||
|
# GOTCHA (2026-06-06): right after login `ollama list` can return EMPTY even though
|
||||||
|
# D:\OllamaModels is fully populated - the tray app's server needs a few seconds to
|
||||||
|
# hydrate its model-list cache. Do NOT treat an empty list as "models gone" or you
|
||||||
|
# re-download 48 GB for nothing. If manifests are on disk, restart + wait first.
|
||||||
|
$listed = (ollama list 2>$null | Out-String).Trim() -split "`n" | Select-Object -Skip 1
|
||||||
|
if ((Test-Path 'D:\OllamaModels\manifests') -and -not $listed) {
|
||||||
|
Warn "ollama list empty but D:\OllamaModels populated - restarting ollama, waiting for hydration"
|
||||||
|
Get-Process 'ollama','ollama app' -ErrorAction SilentlyContinue | Stop-Process -Force; Start-Sleep 2
|
||||||
|
$oapp = "$env:LOCALAPPDATA\Programs\Ollama\ollama app.exe"
|
||||||
|
if (Test-Path $oapp) { Start-Process $oapp } else { Start-Process ollama -ArgumentList 'serve' -WindowStyle Hidden }
|
||||||
|
Start-Sleep 10
|
||||||
|
}
|
||||||
$have = (ollama list 2>$null | Out-String)
|
$have = (ollama list 2>$null | Out-String)
|
||||||
foreach ($m in $models) {
|
foreach ($m in $models) {
|
||||||
$short = $m -replace ':latest$',''
|
$short = $m -replace ':latest$',''
|
||||||
|
|||||||
@@ -62,6 +62,24 @@ Recovery bundle on **E:** and **F:** (`\claudetools-recovery\`). Refresh it with
|
|||||||
|
|
||||||
## Known issues
|
## Known issues
|
||||||
|
|
||||||
|
- **Two Python interpreters, both must have deps.** `py` -> Python **3.14** (vault
|
||||||
|
`yaml-query.py`/get-field needs PyYAML; helper + skill scripts; scheduled tasks).
|
||||||
|
`python` -> Python **3.12** (the interpreter `.mcp.json` launches MCP servers with;
|
||||||
|
ticktick needs `httpx` + `mcp`). The 2026-06-06 reinstall installed deps into only
|
||||||
|
`py`, so ticktick MCP and `vault get-field` were both dead. `windows-bootstrap.ps1`
|
||||||
|
Phase 7 now installs into BOTH interpreters. Also `websocket-client` (cdp.py) under `py`.
|
||||||
|
- **Ollama models survive on `D:\OllamaModels` (~48 GB) but `ollama list` can read empty
|
||||||
|
right after login** — the tray app's server takes a few seconds to hydrate its
|
||||||
|
model-list cache. Don't treat empty as "models gone" / re-download. Restart the app
|
||||||
|
(or `ollama serve` with `OLLAMA_MODELS=D:\OllamaModels`) and wait ~10s. Bootstrap
|
||||||
|
Phase 8 handles this. The 5 expected models: nomic-embed-text, qwen3:8b, qwen3:14b,
|
||||||
|
codestral:22b, qwen3.6:latest.
|
||||||
|
- **grok CLI** is a bare `~\.grok\bin\grok.exe` drop; its installer doesn't touch PATH.
|
||||||
|
Bootstrap Phase 3 now persists `~\.grok\bin` (+ `~\.local\bin`, `%APPDATA%\npm`) to User PATH.
|
||||||
|
- **Git auth must be non-interactive** (no GCM password prompts — they hang automation).
|
||||||
|
Primed by `.claude/scripts/setup-git-auth.sh` (vault token -> `store` helper, per-repo
|
||||||
|
host) via a SessionStart hook + bootstrap Phase 6; `GIT_TERMINAL_PROMPT=0` is enforced
|
||||||
|
in `.claude/settings.json`. See memory `feedback_git_noninteractive_auth`.
|
||||||
- Old `D:\work\gururmm` remote URL embedded the shared Gitea password in plaintext —
|
- Old `D:\work\gururmm` remote URL embedded the shared Gitea password in plaintext —
|
||||||
reset to a clean URL + Windows Credential Manager on rebuild.
|
reset to a clean URL + Windows Credential Manager on rebuild.
|
||||||
- (Hardware) RTX 5070 Ti GSP firmware bug under sustained GPU compute — see `acg-guru-5070.md`.
|
- (Hardware) RTX 5070 Ti GSP firmware bug under sustained GPU compute — see `acg-guru-5070.md`.
|
||||||
|
|||||||
Reference in New Issue
Block a user