From 4a2953a2f17937bb45354a92ad967ae4519c55c5 Mon Sep 17 00:00:00 2001 From: Rainman74 Date: Mon, 18 May 2026 17:58:25 +0200 Subject: [PATCH 1/6] Added RESUME.bat --- RESUME.bat | 191 +++++++++++ tools/Open_Dashboard.bat | 206 +++++------ tools/Setup_Local_Models.bat | 24 +- tools/setup_local_models.ps1 | 642 +++++++++++++++++------------------ 4 files changed, 627 insertions(+), 436 deletions(-) create mode 100644 RESUME.bat diff --git a/RESUME.bat b/RESUME.bat new file mode 100644 index 0000000..1d4d725 --- /dev/null +++ b/RESUME.bat @@ -0,0 +1,191 @@ +@echo off & setlocal enabledelayedexpansion +chcp 65001 >nul +title OpenClaude - Resume Last Session +goto :INIT + +:INIT +set "ENGINE_DIR=%~dp0engine\" +set "USB_ROOT=%ENGINE_DIR%..\" +set "DATA_DIR=%USB_ROOT%data" +set "ENV_FILE=%DATA_DIR%\ai_settings.env" +set "NODE_DIR=%ENGINE_DIR%node-win-x64" +set "GIT_DIR=%ENGINE_DIR%git-win-x64" +set "GIT_BASH=%GIT_DIR%\bin\bash.exe" +set "GIT_EXE=%GIT_DIR%\bin\git.exe" +set "OC_BIN=%ENGINE_DIR%node_modules\@gitlawb\openclaude\bin\openclaude" + +set "CLAUDE_CONFIG_DIR=%DATA_DIR%\openclaude" +set "PORTABLE_HOME=%DATA_DIR%\home" +set "XDG_CONFIG_HOME=%DATA_DIR%\config" +set "XDG_DATA_HOME=%DATA_DIR%\app_data" +set "XDG_CACHE_HOME=%DATA_DIR%\cache" +set "APPDATA=%DATA_DIR%\app_data" +set "LOCALAPPDATA=%DATA_DIR%\local_app_data" +set "HOME=%PORTABLE_HOME%" +set "USERPROFILE=%PORTABLE_HOME%" + +set "PATH=%NODE_DIR%;%GIT_DIR%\cmd;%GIT_DIR%\bin;%GIT_DIR%\usr\bin;%PATH%" +set "CLAUDE_CODE_GIT_BASH_PATH=%GIT_BASH%" +goto :MAIN + +:MAIN +if not exist "%NODE_DIR%\node.exe" ( + echo [ERROR] Node.js was not found: %NODE_DIR%\node.exe + echo Please run START.bat first. + pause + exit /b 1 +) + +if not exist "%GIT_BASH%" ( + echo [ERROR] Git Bash was not found: %GIT_BASH% + echo Please run START.bat first. + pause + exit /b 1 +) + +if not exist "%GIT_EXE%" ( + echo [ERROR] Git executable was not found: %GIT_EXE% + echo Please run START.bat first. + pause + exit /b 1 +) + +if not exist "%OC_BIN%" ( + echo [ERROR] OpenClaude was not found: %OC_BIN% + echo Please run START.bat first. + pause + exit /b 1 +) + +if exist "%ENV_FILE%" ( + for /f "usebackq tokens=1,* delims==" %%A in ("%ENV_FILE%") do ( + set "%%A=%%~B" + ) +) else ( + echo [WARN] No provider configuration found: %ENV_FILE% +) + +if not "!AI_PROVIDER!" == "anthropic" ( + set "ANTHROPIC_API_KEY=" +) + +set "SESSION_ID=" +set "WORK_DIR=" + +if "%~1" == "" goto ARGS_DONE + +if /i "%~1" == "--cwd" ( + set "WORK_DIR=%~2" + goto ARGS_DONE +) + +if /i "%~1" == "--resume" ( + set "SESSION_ID=%~2" + if /i "%~3" == "--cwd" ( + set "WORK_DIR=%~4" + ) else ( + set "WORK_DIR=%~3" + ) + goto ARGS_DONE +) + +if exist "%~1\" ( + set "WORK_DIR=%~1" + goto ARGS_DONE +) + +set "SESSION_ID=%~1" +if /i "%~2" == "--cwd" ( + set "WORK_DIR=%~3" +) else ( + set "WORK_DIR=%~2" +) + +:ARGS_DONE +if /i "%~1" == "--resume" ( + if not defined SESSION_ID ( + echo [ERROR] No session ID provided after --resume. + pause + exit /b 1 + ) +) +if /i "%~1" == "--cwd" ( + if not defined WORK_DIR ( + echo [ERROR] No working directory provided after --cwd. + pause + exit /b 1 + ) +) +if /i "%~2" == "--cwd" ( + if not defined WORK_DIR ( + echo [ERROR] No working directory provided after --cwd. + pause + exit /b 1 + ) +) +if /i "%~3" == "--cwd" ( + if not defined WORK_DIR ( + echo [ERROR] No working directory provided after --cwd. + pause + exit /b 1 + ) +) +if not defined WORK_DIR set "WORK_DIR=%ENGINE_DIR%" + +if not exist "!WORK_DIR!\" ( + echo [ERROR] Working directory was not found: !WORK_DIR! + pause + exit /b 1 +) + +set "PROVIDER_ARGS=" +if defined AI_PROVIDER set "PROVIDER_ARGS=--provider !AI_PROVIDER!" +set "CMD_ARGS=--dangerously-skip-permissions" + +if not "!AI_PROVIDER!" == "ollama" goto SKIP_OLLAMA_START +if not exist "%DATA_DIR%\ollama\ollama.exe" goto SKIP_OLLAMA_START + +echo [~] Starting Local Ollama Server... +set "OLLAMA_MODELS=%DATA_DIR%\ollama\data" +start "Ollama Portable" /b /min "%DATA_DIR%\ollama\ollama.exe" serve >nul 2>&1 +timeout /t 3 /nobreak >nul +echo [OK] Ollama running! +if not exist "%USB_ROOT%tools\local-proxy.js" goto SKIP_PROXY_START +echo [~] Starting local speed proxy... +powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'Name = ''node.exe''' | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 +start "LocalProxy" /b /min "%NODE_DIR%\node.exe" "%USB_ROOT%tools\local-proxy.js" +timeout /t 2 /nobreak >nul +set "OPENAI_BASE_URL=http://localhost:11435/v1" +echo [OK] Speed proxy active. +:SKIP_PROXY_START + +:SKIP_OLLAMA_START + +pushd "!WORK_DIR!" +if defined SESSION_ID ( + call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --resume "!SESSION_ID!" + set "OC_STATUS=!ERRORLEVEL!" +) else ( + call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --continue + set "OC_STATUS=!ERRORLEVEL!" + if not "!OC_STATUS!" == "0" ( + echo [WARN] No conversation found to continue. Starting a new session in the current working directory... + call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! + set "OC_STATUS=!ERRORLEVEL!" + ) +) +popd + +if not "!AI_PROVIDER!" == "ollama" goto SKIP_OLLAMA_STOP +if not exist "%DATA_DIR%\ollama\ollama.exe" goto SKIP_OLLAMA_STOP +echo. +echo [~] Stopping Local Ollama Server... +taskkill /f /im ollama.exe >nul 2>&1 +powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'Name = ''node.exe''' | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 +:SKIP_OLLAMA_STOP + +pause +goto :END + +:END +exit /b !OC_STATUS! diff --git a/tools/Open_Dashboard.bat b/tools/Open_Dashboard.bat index b593a69..325f021 100644 --- a/tools/Open_Dashboard.bat +++ b/tools/Open_Dashboard.bat @@ -1,103 +1,103 @@ -@echo off -setlocal enabledelayedexpansion -title Portable AI USB - Dashboard - -:: Define ANSI Colors using PowerShell -for /F %%a in ('powershell -NoProfile -Command "[char]27"') do set "ESC=%%a" -set "CYAN=%ESC%[36m" -set "GREEN=%ESC%[32m" -set "YELLOW=%ESC%[33m" -set "RED=%ESC%[31m" -set "DIM=%ESC%[90m" -set "R=%ESC%[0m" -set "BOLD=%ESC%[1m" - -set "USB_ROOT=%~dp0..\" -set "ENGINE_DIR=%USB_ROOT%engine" -set "NODE=%ENGINE_DIR%\node-win-x64\node.exe" -set "DASHBOARD=%USB_ROOT%dashboard\server.mjs" -set "DATA_DIR=%USB_ROOT%data" - -:: Portable data - keep everything on USB -set "CLAUDE_CONFIG_DIR=%DATA_DIR%\openclaude" -set "XDG_CONFIG_HOME=%DATA_DIR%\config" -set "XDG_DATA_HOME=%DATA_DIR%\app_data" -if not exist "%CLAUDE_CONFIG_DIR%" mkdir "%CLAUDE_CONFIG_DIR%" -if not exist "%XDG_CONFIG_HOME%" mkdir "%XDG_CONFIG_HOME%" -if not exist "%XDG_DATA_HOME%" mkdir "%XDG_DATA_HOME%" - -echo. -echo %CYAN%=========================================================%R% -echo %BOLD%Portable AI USB - Configuration Dashboard%R% -echo %CYAN%=========================================================%R% -echo. - -:: Check Node.js -if not exist "%NODE%" goto err_nonode - -:: Check dashboard file -if not exist "%DASHBOARD%" goto err_nodash - -:: Check if port 3000 is already in use -set "PORT_BUSY=0" -netstat -ano 2>nul | findstr ":3000 " | findstr "LISTENING" >nul 2>&1 -if not errorlevel 1 set "PORT_BUSY=1" - -if "%PORT_BUSY%"=="1" goto port_conflict - -echo %CYAN%[~] Starting dashboard server...%R% -echo %DIM%Dashboard will be available at %BOLD%http://localhost:3000%R% -echo. - -:: Open browser -start "" "http://localhost:3000" - -echo %GREEN%[OK] Browser opened!%R% -echo %DIM%Press Ctrl+C to stop the dashboard.%R% -echo. - -"%NODE%" "%DASHBOARD%" -pause -goto :eof - -:: --------------------------------------------------------- -:: ERROR HANDLERS -:: --------------------------------------------------------- -:err_nonode -echo %RED%[ERROR] Node.js not found.%R% -echo %YELLOW%Please run START.bat first.%R% -echo. -pause -goto :eof - -:err_nodash -echo %RED%[ERROR] Dashboard files not found!%R% -echo %YELLOW%Expected: %DASHBOARD%%R% -echo. -pause -goto :eof - -:port_conflict -echo %YELLOW%[WARNING] Port 3000 is already in use!%R% -echo. -echo %DIM%Another application is using port 3000.%R% -echo %DIM%The dashboard may already be running.%R% -echo. -echo %CYAN%1)%R% Open browser anyway (dashboard may already be running) -echo %CYAN%2)%R% Cancel -echo. -set "PORT_CHOICE=" -set /p "PORT_CHOICE= Select (1 or 2): " -if "%PORT_CHOICE%"=="1" ( - echo. - echo %CYAN%[~] Opening browser...%R% - start "" "http://localhost:3000" - echo %GREEN%[OK] Browser opened!%R% - echo. - pause - goto :eof -) -echo. -echo %DIM%Cancelled.%R% -pause -goto :eof +@echo off +setlocal enabledelayedexpansion +title Portable AI USB - Dashboard + +:: Define ANSI Colors using PowerShell +for /F %%a in ('powershell -NoProfile -Command "[char]27"') do set "ESC=%%a" +set "CYAN=%ESC%[36m" +set "GREEN=%ESC%[32m" +set "YELLOW=%ESC%[33m" +set "RED=%ESC%[31m" +set "DIM=%ESC%[90m" +set "R=%ESC%[0m" +set "BOLD=%ESC%[1m" + +set "USB_ROOT=%~dp0..\" +set "ENGINE_DIR=%USB_ROOT%engine" +set "NODE=%ENGINE_DIR%\node-win-x64\node.exe" +set "DASHBOARD=%USB_ROOT%dashboard\server.mjs" +set "DATA_DIR=%USB_ROOT%data" + +:: Portable data - keep everything on USB +set "CLAUDE_CONFIG_DIR=%DATA_DIR%\openclaude" +set "XDG_CONFIG_HOME=%DATA_DIR%\config" +set "XDG_DATA_HOME=%DATA_DIR%\app_data" +if not exist "%CLAUDE_CONFIG_DIR%" mkdir "%CLAUDE_CONFIG_DIR%" +if not exist "%XDG_CONFIG_HOME%" mkdir "%XDG_CONFIG_HOME%" +if not exist "%XDG_DATA_HOME%" mkdir "%XDG_DATA_HOME%" + +echo. +echo %CYAN%=========================================================%R% +echo %BOLD%Portable AI USB - Configuration Dashboard%R% +echo %CYAN%=========================================================%R% +echo. + +:: Check Node.js +if not exist "%NODE%" goto err_nonode + +:: Check dashboard file +if not exist "%DASHBOARD%" goto err_nodash + +:: Check if port 3000 is already in use +set "PORT_BUSY=0" +netstat -ano 2>nul | findstr ":3000 " | findstr "LISTENING" >nul 2>&1 +if not errorlevel 1 set "PORT_BUSY=1" + +if "%PORT_BUSY%"=="1" goto port_conflict + +echo %CYAN%[~] Starting dashboard server...%R% +echo %DIM%Dashboard will be available at %BOLD%http://localhost:3000%R% +echo. + +:: Open browser +start "" "http://localhost:3000" + +echo %GREEN%[OK] Browser opened!%R% +echo %DIM%Press Ctrl+C to stop the dashboard.%R% +echo. + +"%NODE%" "%DASHBOARD%" +pause +goto :eof + +:: --------------------------------------------------------- +:: ERROR HANDLERS +:: --------------------------------------------------------- +:err_nonode +echo %RED%[ERROR] Node.js not found.%R% +echo %YELLOW%Please run START.bat first.%R% +echo. +pause +goto :eof + +:err_nodash +echo %RED%[ERROR] Dashboard files not found!%R% +echo %YELLOW%Expected: %DASHBOARD%%R% +echo. +pause +goto :eof + +:port_conflict +echo %YELLOW%[WARNING] Port 3000 is already in use!%R% +echo. +echo %DIM%Another application is using port 3000.%R% +echo %DIM%The dashboard may already be running.%R% +echo. +echo %CYAN%1)%R% Open browser anyway (dashboard may already be running) +echo %CYAN%2)%R% Cancel +echo. +set "PORT_CHOICE=" +set /p "PORT_CHOICE= Select (1 or 2): " +if "%PORT_CHOICE%"=="1" ( + echo. + echo %CYAN%[~] Opening browser...%R% + start "" "http://localhost:3000" + echo %GREEN%[OK] Browser opened!%R% + echo. + pause + goto :eof +) +echo. +echo %DIM%Cancelled.%R% +pause +goto :eof diff --git a/tools/Setup_Local_Models.bat b/tools/Setup_Local_Models.bat index bcd9c60..86a23bf 100644 --- a/tools/Setup_Local_Models.bat +++ b/tools/Setup_Local_Models.bat @@ -1,12 +1,12 @@ -@echo off -title Portable AI USB - Local Model Setup -cls - -echo. -echo Running Local Model Setup... -echo. - -powershell -ExecutionPolicy Bypass -NoProfile -File "%~dp0setup_local_models.ps1" - -echo. -pause +@echo off +title Portable AI USB - Local Model Setup +cls + +echo. +echo Running Local Model Setup... +echo. + +powershell -ExecutionPolicy Bypass -NoProfile -File "%~dp0setup_local_models.ps1" + +echo. +pause diff --git a/tools/setup_local_models.ps1 b/tools/setup_local_models.ps1 index ce985fd..d501133 100644 --- a/tools/setup_local_models.ps1 +++ b/tools/setup_local_models.ps1 @@ -1,321 +1,321 @@ -$ErrorActionPreference = "Continue" -$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path -$RootDir = (Resolve-Path "$ScriptDir\..").Path -$DataDir = "$RootDir\data" -$EnvFile = "$DataDir\ai_settings.env" -$ModelsDir = "$DataDir\models" -$OllamaDir = "$DataDir\ollama" - -$ModelCatalog = @( - # Category 1: Gemma 4 Family (Optimized GGUFs) - @{ Num=1; Category="Gemma 4 Family (Optimized GGUFs)"; Name="Gemma 4 E2B (Q4_K_M)"; Tag="https://huggingface.co/unsloth/gemma-4-E2B-it-GGUF/resolve/main/gemma-4-E2B-it-Q4_K_M.gguf"; Size="3.1"; Input="Text"; Label="STANDARD"; Badge="BEST BALANCE" }, - @{ Num=2; Category="Gemma 4 Family (Optimized GGUFs)"; Name="Gemma 4 E2B (Q6_K)"; Tag="https://huggingface.co/unsloth/gemma-4-E2B-it-GGUF/resolve/main/gemma-4-E2B-it-Q6_K.gguf"; Size="4.5"; Input="Text"; Label="STANDARD"; Badge="STRONG CPU/GPU" }, - @{ Num=3; Category="Gemma 4 Family (Optimized GGUFs)"; Name="Gemma 4 E4B (Q4_K_M)"; Tag="https://huggingface.co/unsloth/gemma-4-E4B-it-GGUF/resolve/main/gemma-4-E4B-it-Q4_K_M.gguf"; Size="5.0"; Input="Text"; Label="STANDARD"; Badge="MOST USERS" }, - - # Category 2: Qwen 3.5 & Ministral 3 - @{ Num=4; Category="Qwen 3.5 & Ministral 3 (Daily Drivers)"; Name="Qwen 3.5 (9B)"; Tag="qwen3.5:9b"; Size="6.6"; Input="Text, Image"; Label="STANDARD"; Badge="RECOMMENDED" }, - @{ Num=5; Category="Qwen 3.5 & Ministral 3 (Daily Drivers)"; Name="Ministral 3 (8B)"; Tag="ministral-3:8b"; Size="6.0"; Input="Text, Image"; Label="STANDARD"; Badge="DAILY" } -) - -function Get-USBFreeSpaceGB { - try { - $driveLetter = (Get-Item $ScriptDir).PSDrive.Name - $drive = Get-PSDrive $driveLetter -ErrorAction SilentlyContinue - if ($drive) { return [math]::Round($drive.Free / 1GB, 1) } - } catch {} - return -1 -} - -Write-Host "" -Write-Host "==========================================================" -ForegroundColor Cyan -Write-Host " PORTABLE AI USB - Local Model Setup (Official)" -ForegroundColor Cyan -Write-Host "==========================================================" -ForegroundColor Cyan -Write-Host "" - -$freeGB = Get-USBFreeSpaceGB -if ($freeGB -gt 0) { Write-Host " USB Free Space: $freeGB GB" -ForegroundColor DarkGray; Write-Host "" } - -Write-Host "[1/4] Choose your AI model(s):" -ForegroundColor Yellow - -$currentCategory = "" -foreach ($m in $ModelCatalog) { - if ($m.Category -ne $currentCategory) { - $currentCategory = $m.Category - Write-Host "`n --- $currentCategory ---" -ForegroundColor Cyan - } - - if ($m.Label -eq "UNCENSORED") { $labelColor = "Red"; $labelStr = " [UNCENSORED]" } - elseif ($m.Label -in @("UTILITY", "VISION", "POWERFUL")) { $labelColor = "DarkYellow"; $labelStr = " [$($m.Label)]" } - elseif ($m.Label -eq "CLOUD") { $labelColor = "Magenta"; $labelStr = " [CLOUD-API]" } - else { $labelColor = "DarkCyan"; $labelStr = " [STANDARD]" } - - $badgeStr = if ($m.Badge) { " - $($m.Badge)" } else { "" } - - $padNum = $m.Num.ToString().PadLeft(2) - Write-Host " [$padNum]" -ForegroundColor Yellow -NoNewline - Write-Host " $($m.Name.PadRight(24))" -ForegroundColor White -NoNewline - Write-Host ("[" + $m.Input + "]").PadRight(16) -ForegroundColor DarkCyan -NoNewline - - $sizeStr = if ($m.Size -eq "-") { " (-)".PadRight(12) } else { " (~$($m.Size) GB)".PadRight(12) } - Write-Host $sizeStr -ForegroundColor DarkGray -NoNewline - - Write-Host $labelStr -ForegroundColor $labelColor -NoNewline - Write-Host $badgeStr -ForegroundColor Magenta -} - -# --- Detect Already Downloaded Models (not in preset list) --- -$ManifestDir = "$OllamaDir\data\manifests\registry.ollama.ai\library" -$DlStartNum = 6 -$DlCount = 0 - -if (Test-Path $ManifestDir) { - $PresetSkipRegex = 'gemma-4-e2b-it-q4_k_m-local|gemma-4-e2b-it-q6_k-local|gemma-4-e4b-it-q4_k_m-local|qwen3.5|ministral-3' - $ModelDirs = Get-ChildItem -Path $ManifestDir -Directory -ErrorAction SilentlyContinue - - foreach ($dir in $ModelDirs) { - $modelBase = $dir.Name - $TagFiles = Get-ChildItem -Path $dir.FullName -File -ErrorAction SilentlyContinue - foreach ($file in $TagFiles) { - $tagName = $file.Name - $fullTag = if ($tagName -eq "latest") { $modelBase } else { "${modelBase}:${tagName}" } - - if ($fullTag -match $PresetSkipRegex) { continue } - - # Read JSON size simply (using regex to avoid full parsing overhead if invalid JSON) - $content = Get-Content $file.FullName -Raw -ErrorAction SilentlyContinue - if ($content -match '"size"\s*:\s*(\d+)') { - $sizeBytes = [long]$matches[1] - if ($sizeBytes -lt 100000000) { continue } # Skip < 100MB - - $sizeGB = [math]::Round($sizeBytes / 1GB, 1) - $Num = $DlStartNum + $DlCount - - # Append to ModelCatalog so existing selection logic works automatically - $ModelCatalog += @{ Num=$Num; Category="Already Downloaded"; Name=$fullTag; Tag=$fullTag; Size=$sizeGB.ToString(); Input="Text"; Label="DOWNLOADED"; Badge="" } - $DlCount++ - } - } - } -} - -if ($DlCount -gt 0) { - Write-Host "`n --- " -ForegroundColor Cyan -NoNewline - Write-Host "Already Downloaded" -ForegroundColor Green -NoNewline - Write-Host " ---" -ForegroundColor Cyan - - $dlModels = $ModelCatalog | Where-Object { $_.Category -eq "Already Downloaded" } - foreach ($m in $dlModels) { - $padNum = $m.Num.ToString().PadLeft(2) - Write-Host " [$padNum]" -ForegroundColor Yellow -NoNewline - Write-Host " $($m.Name.PadRight(24))" -ForegroundColor White -NoNewline - Write-Host ("[" + $m.Input + "]").PadRight(16) -ForegroundColor DarkCyan -NoNewline - Write-Host " (~$($m.Size) GB)".PadRight(12) -ForegroundColor DarkGray -NoNewline - Write-Host " [DOWNLOADED]" -ForegroundColor Green - } -} - -Write-Host "`n [C] CUSTOM - Enter an Official Ollama Tag" -ForegroundColor Green -Write-Host " Browse ALL models here: " -ForegroundColor Gray -NoNewline -Write-Host "https://ollama.com/library" -ForegroundColor Blue -Write-Host "`n ------------------------------------------------" -ForegroundColor DarkGray -Write-Host " Enter number(s) separated by commas (e.g. 1,4)" -ForegroundColor Gray -Write-Host " Type 'all' for every preset model, 'c' for custom`n" -ForegroundColor Gray - -$UserChoice = Read-Host " Your choice" -if ([string]::IsNullOrWhiteSpace($UserChoice)) { - Write-Host "`n No input! Defaulting to [3] Gemma 4 E4B..." -ForegroundColor Yellow - $UserChoice = "3" -} - -$SelectedModels = @() -$HasCustom = $false - -if ($UserChoice.Trim().ToLower() -eq "all") { $SelectedModels = @($ModelCatalog) } -else { - foreach ($t in ($UserChoice -split "," | ForEach-Object { $_.Trim().ToLower() })) { - if ($t -eq "c" -or $t -eq "custom") { $HasCustom = $true } - elseif ($t -match '^\d+$') { - $num = [int]$t - $found = $ModelCatalog | Where-Object { $_.Num -eq $num } - if ($found -and -Not ($SelectedModels | Where-Object { $_.Num -eq $num })) { $SelectedModels += $found } - } - } -} - -if ($HasCustom) { - Write-Host "`n ---- Custom Model Setup ----" -ForegroundColor Green - $customTag = Read-Host " Ollama Tag (e.g. mistral-nemo, phi3)" - if ($customTag) { - $customName = (CultureInfo.CurrentCulture.TextInfo.ToTitleCase($customTag.ToLower())) - $SelectedModels += @{ Num=99; Name="Custom: $customName"; Tag=$customTag.Trim(); Size="?"; Label="CUSTOM" } - Write-Host " Custom model added!" -ForegroundColor Green - } -} - -if ($SelectedModels.Count -eq 0) { Write-Host "`n ERROR: No models selected!" -ForegroundColor Red; exit 1 } - -$totalSizeGB = 0 -foreach ($m in $SelectedModels) { - if ($m.Size -match '\d') { $totalSizeGB += [double]$m.Size } -} - -if ($totalSizeGB -ge ($freeGB - 1) -and $freeGB -gt 0 -or $UserChoice.Trim().ToLower() -eq "all") { - Write-Host "`n WARNING: These models total ~$([math]::Ceiling($totalSizeGB)) GB. USB drive has $freeGB GB free!" -ForegroundColor Red - $confirm = Read-Host " Continue? (yes/no)" - if ($confirm.Trim().ToLower() -ne "yes" -and $confirm.Trim().ToLower() -ne "y") { exit } -} - -# Directories -New-Item -ItemType Directory -Force -Path $ModelsDir | Out-Null -New-Item -ItemType Directory -Force -Path "$OllamaDir\data" | Out-Null -Write-Host "`n[2/4] Created storage folders." -ForegroundColor Green - -# Ollama Engine Setup -Write-Host "`n[3/4] Setting up Portable Ollama Engine..." -ForegroundColor Yellow -$OllamaURL = "https://github.com/ollama/ollama/releases/latest/download/ollama-windows-amd64.zip" -$OllamaDest = "$OllamaDir\ollama.zip" -$OllamaExe = "$OllamaDir\ollama.exe" - -if (Test-Path $OllamaExe) { - Write-Host " Engine already installed!" -ForegroundColor Green -} else { - Write-Host " Downloading Ollama Engine (~100MB)..." -ForegroundColor Yellow - curl.exe -L --ssl-no-revoke $OllamaURL -o $OllamaDest - if (Test-Path $OllamaDest) { - Write-Host " Extracting to USB..." -ForegroundColor Yellow - Expand-Archive -Path $OllamaDest -DestinationPath $OllamaDir -Force - Remove-Item $OllamaDest -Force -ErrorAction SilentlyContinue - Write-Host " Engine Installed successfully!" -ForegroundColor Green - } else { - Write-Host " ERROR: Failed to download engine!" -ForegroundColor Red - exit 1 - } -} - -# Downloading Models via Ollama -Write-Host "`n[4/4] Pulling Models (This guarantees perfectly configured Tool Support)..." -ForegroundColor Yellow - -$downloadErrors = @() - -$env:OLLAMA_MODELS = "$OllamaDir\data" -Write-Host "`n Starting background Ollama server on USB..." -ForegroundColor DarkGray -$ServerProcess = Start-Process -FilePath $OllamaExe -ArgumentList "serve" -WindowStyle Hidden -PassThru -Start-Sleep -Seconds 5 - -$idx = 1 -foreach ($m in $SelectedModels) { - if ($m.Tag -match "^http.*" -and $m.Tag -match "\.gguf") { - $tagUrlNoQuery = $m.Tag.Split('?')[0] - $fileName = $tagUrlNoQuery.Split('/')[-1] - if (-not $fileName.EndsWith(".gguf")) { $fileName += ".gguf" } - $dest = "$ModelsDir\$fileName" - - $baseName = $fileName -ireplace '\.gguf$', '' - $modelNameLocal = "$baseName-local".ToLower() -replace '[^a-z0-9_-]', '-' - - # --- Always verify real file size against server --- - Write-Host "`n ($idx/$($SelectedModels.Count)) Checking $($m.Name)..." -ForegroundColor Yellow - $idx++ - - $expectedSize = 0 - $existingSize = 0 - try { - $headResponse = Invoke-WebRequest -Uri $m.Tag -Method Head -UseBasicParsing -ErrorAction Stop - $expectedSize = [long]$headResponse.Headers['Content-Length'] - } catch {} - if (Test-Path $dest) { $existingSize = (Get-Item $dest).Length } - - $fileComplete = ($expectedSize -gt 0 -and $existingSize -ge $expectedSize) - - # Only skip if file is FULLY downloaded AND ollama has it imported - $showResult = & $OllamaExe show $modelNameLocal 2>&1 - if ($fileComplete -and $LASTEXITCODE -eq 0) { - $existMegabytes = [math]::Round($existingSize / 1MB) - Write-Host (" $([char]0x2705) {0} fully downloaded ({1} MB) & imported - skipping!" -f $m.Name, $existMegabytes) -ForegroundColor Green - $m.Tag = $modelNameLocal - continue - } - - Write-Host " Do not close this window! Download may take a while." -ForegroundColor Magenta - - try { - # --- Download or resume --- - if ((Test-Path $dest) -and -not $fileComplete) { - $existMegabytes = [math]::Round($existingSize / 1MB) - $expectMegabytes = [math]::Round($expectedSize / 1MB) - Write-Host (" {0} is incomplete ({1} MB / {2} MB). Resuming..." -f $fileName, $existMegabytes, $expectMegabytes) -ForegroundColor Yellow - curl.exe -L -C - $($m.Tag) -o $dest - } elseif (-not $fileComplete) { - Write-Host " Downloading $fileName (speed + ETA shown below)..." -ForegroundColor Cyan - curl.exe -L -C - $($m.Tag) -o $dest - } - - $modelFileContent = "FROM ./$fileName`nPARAMETER temperature 0.7`nPARAMETER top_p 0.9" - $modelFilePath = "$ModelsDir\Modelfile-$modelNameLocal" - Set-Content -Path $modelFilePath -Value $modelFileContent -Encoding Ascii - - Write-Host " Importing into Ollama as '$modelNameLocal'..." -ForegroundColor Cyan - Push-Location $ModelsDir - $createArgs = "create $modelNameLocal -f Modelfile-$modelNameLocal" - $createProcess = Start-Process -FilePath $OllamaExe -ArgumentList $createArgs -Wait -NoNewWindow -PassThru - Pop-Location - - if ($createProcess.ExitCode -eq 0) { - Write-Host " Import complete!" -ForegroundColor Green - $m.Tag = $modelNameLocal - } else { - throw "Exit code $($createProcess.ExitCode)" - } - } catch { - Write-Host " FAILED to import custom model: $fileName" -ForegroundColor Red - $downloadErrors += $m.Name - } - continue - } - - # --- Check if standard Ollama model already exists --- - $showResult = & $OllamaExe show $($m.Tag) 2>&1 - if ($LASTEXITCODE -eq 0) { - Write-Host "`n ($idx/$($SelectedModels.Count)) " -ForegroundColor Green -NoNewline - Write-Host ("$([char]0x2705) {0} [{1}] already pulled - skipping!" -f $m.Name, $m.Tag) -ForegroundColor Green - $idx++ - continue - } - - Write-Host "`n ($idx/$($SelectedModels.Count)) Pulling $($m.Name) [$($m.Tag)]..." -ForegroundColor Yellow - Write-Host " Do not close this window! Download may take a while depending on bandwidth." -ForegroundColor Magenta - $idx++ - - try { - $pullArgs = "pull $($m.Tag)" - $pullProcess = Start-Process -FilePath $OllamaExe -ArgumentList $pullArgs -Wait -NoNewWindow -PassThru - if ($pullProcess.ExitCode -ne 0) { throw "Exit code $($pullProcess.ExitCode)" } - Write-Host " Pull complete!" -ForegroundColor Green - } catch { - Write-Host " FAILED to pull model: $($m.Tag)" -ForegroundColor Red - $downloadErrors += $m.Name - } -} - -Write-Host "`n Stopping background Ollama server..." -ForegroundColor DarkGray -Stop-Process -Id $ServerProcess.Id -Force -ErrorAction SilentlyContinue - -# Record Models for the Dashboard -$installedList = $SelectedModels | ForEach-Object { "$($_.Tag)|$($_.Name)|$($_.Label)" } -if (Test-Path "$ModelsDir\installed-models.txt") { - $existing = Get-Content "$ModelsDir\installed-models.txt" - $installedList = ($existing + $installedList) | Select-Object -Unique -} -Set-Content -Path "$ModelsDir\installed-models.txt" -Value ($installedList -join "`n") -Force -Encoding UTF8 - -Write-Host "`n[5/5] Finalizing Configurations..." -ForegroundColor Yellow - -$firstModelTag = $SelectedModels[0].Tag -$configContent = "AI_PROVIDER=ollama`nCLAUDE_CODE_USE_OPENAI=1`nOPENAI_API_KEY=ollama`nOPENAI_BASE_URL=http://localhost:11434/v1`nOPENAI_MODEL=$firstModelTag`nAI_DISPLAY_MODEL=$firstModelTag" -Set-Content -Path $EnvFile -Value $configContent -Force -Encoding Ascii -Write-Host " Default Model set to: $firstModelTag" -ForegroundColor Green - -Write-Host "`n==========================================================" -ForegroundColor Cyan -if ($downloadErrors.Count -gt 0) { Write-Host " SETUP COMPLETE (with some download errors)" -ForegroundColor Yellow } -else { Write-Host " SETUP COMPLETE! LOCAL AI AGENTS ARE READY!" -ForegroundColor Green } -Write-Host "==========================================================" -ForegroundColor Cyan +$ErrorActionPreference = "Continue" +$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$RootDir = (Resolve-Path "$ScriptDir\..").Path +$DataDir = "$RootDir\data" +$EnvFile = "$DataDir\ai_settings.env" +$ModelsDir = "$DataDir\models" +$OllamaDir = "$DataDir\ollama" + +$ModelCatalog = @( + # Category 1: Gemma 4 Family (Optimized GGUFs) + @{ Num=1; Category="Gemma 4 Family (Optimized GGUFs)"; Name="Gemma 4 E2B (Q4_K_M)"; Tag="https://huggingface.co/unsloth/gemma-4-E2B-it-GGUF/resolve/main/gemma-4-E2B-it-Q4_K_M.gguf"; Size="3.1"; Input="Text"; Label="STANDARD"; Badge="BEST BALANCE" }, + @{ Num=2; Category="Gemma 4 Family (Optimized GGUFs)"; Name="Gemma 4 E2B (Q6_K)"; Tag="https://huggingface.co/unsloth/gemma-4-E2B-it-GGUF/resolve/main/gemma-4-E2B-it-Q6_K.gguf"; Size="4.5"; Input="Text"; Label="STANDARD"; Badge="STRONG CPU/GPU" }, + @{ Num=3; Category="Gemma 4 Family (Optimized GGUFs)"; Name="Gemma 4 E4B (Q4_K_M)"; Tag="https://huggingface.co/unsloth/gemma-4-E4B-it-GGUF/resolve/main/gemma-4-E4B-it-Q4_K_M.gguf"; Size="5.0"; Input="Text"; Label="STANDARD"; Badge="MOST USERS" }, + + # Category 2: Qwen 3.5 & Ministral 3 + @{ Num=4; Category="Qwen 3.5 & Ministral 3 (Daily Drivers)"; Name="Qwen 3.5 (9B)"; Tag="qwen3.5:9b"; Size="6.6"; Input="Text, Image"; Label="STANDARD"; Badge="RECOMMENDED" }, + @{ Num=5; Category="Qwen 3.5 & Ministral 3 (Daily Drivers)"; Name="Ministral 3 (8B)"; Tag="ministral-3:8b"; Size="6.0"; Input="Text, Image"; Label="STANDARD"; Badge="DAILY" } +) + +function Get-USBFreeSpaceGB { + try { + $driveLetter = (Get-Item $ScriptDir).PSDrive.Name + $drive = Get-PSDrive $driveLetter -ErrorAction SilentlyContinue + if ($drive) { return [math]::Round($drive.Free / 1GB, 1) } + } catch {} + return -1 +} + +Write-Host "" +Write-Host "==========================================================" -ForegroundColor Cyan +Write-Host " PORTABLE AI USB - Local Model Setup (Official)" -ForegroundColor Cyan +Write-Host "==========================================================" -ForegroundColor Cyan +Write-Host "" + +$freeGB = Get-USBFreeSpaceGB +if ($freeGB -gt 0) { Write-Host " USB Free Space: $freeGB GB" -ForegroundColor DarkGray; Write-Host "" } + +Write-Host "[1/4] Choose your AI model(s):" -ForegroundColor Yellow + +$currentCategory = "" +foreach ($m in $ModelCatalog) { + if ($m.Category -ne $currentCategory) { + $currentCategory = $m.Category + Write-Host "`n --- $currentCategory ---" -ForegroundColor Cyan + } + + if ($m.Label -eq "UNCENSORED") { $labelColor = "Red"; $labelStr = " [UNCENSORED]" } + elseif ($m.Label -in @("UTILITY", "VISION", "POWERFUL")) { $labelColor = "DarkYellow"; $labelStr = " [$($m.Label)]" } + elseif ($m.Label -eq "CLOUD") { $labelColor = "Magenta"; $labelStr = " [CLOUD-API]" } + else { $labelColor = "DarkCyan"; $labelStr = " [STANDARD]" } + + $badgeStr = if ($m.Badge) { " - $($m.Badge)" } else { "" } + + $padNum = $m.Num.ToString().PadLeft(2) + Write-Host " [$padNum]" -ForegroundColor Yellow -NoNewline + Write-Host " $($m.Name.PadRight(24))" -ForegroundColor White -NoNewline + Write-Host ("[" + $m.Input + "]").PadRight(16) -ForegroundColor DarkCyan -NoNewline + + $sizeStr = if ($m.Size -eq "-") { " (-)".PadRight(12) } else { " (~$($m.Size) GB)".PadRight(12) } + Write-Host $sizeStr -ForegroundColor DarkGray -NoNewline + + Write-Host $labelStr -ForegroundColor $labelColor -NoNewline + Write-Host $badgeStr -ForegroundColor Magenta +} + +# --- Detect Already Downloaded Models (not in preset list) --- +$ManifestDir = "$OllamaDir\data\manifests\registry.ollama.ai\library" +$DlStartNum = 6 +$DlCount = 0 + +if (Test-Path $ManifestDir) { + $PresetSkipRegex = 'gemma-4-e2b-it-q4_k_m-local|gemma-4-e2b-it-q6_k-local|gemma-4-e4b-it-q4_k_m-local|qwen3.5|ministral-3' + $ModelDirs = Get-ChildItem -Path $ManifestDir -Directory -ErrorAction SilentlyContinue + + foreach ($dir in $ModelDirs) { + $modelBase = $dir.Name + $TagFiles = Get-ChildItem -Path $dir.FullName -File -ErrorAction SilentlyContinue + foreach ($file in $TagFiles) { + $tagName = $file.Name + $fullTag = if ($tagName -eq "latest") { $modelBase } else { "${modelBase}:${tagName}" } + + if ($fullTag -match $PresetSkipRegex) { continue } + + # Read JSON size simply (using regex to avoid full parsing overhead if invalid JSON) + $content = Get-Content $file.FullName -Raw -ErrorAction SilentlyContinue + if ($content -match '"size"\s*:\s*(\d+)') { + $sizeBytes = [long]$matches[1] + if ($sizeBytes -lt 100000000) { continue } # Skip < 100MB + + $sizeGB = [math]::Round($sizeBytes / 1GB, 1) + $Num = $DlStartNum + $DlCount + + # Append to ModelCatalog so existing selection logic works automatically + $ModelCatalog += @{ Num=$Num; Category="Already Downloaded"; Name=$fullTag; Tag=$fullTag; Size=$sizeGB.ToString(); Input="Text"; Label="DOWNLOADED"; Badge="" } + $DlCount++ + } + } + } +} + +if ($DlCount -gt 0) { + Write-Host "`n --- " -ForegroundColor Cyan -NoNewline + Write-Host "Already Downloaded" -ForegroundColor Green -NoNewline + Write-Host " ---" -ForegroundColor Cyan + + $dlModels = $ModelCatalog | Where-Object { $_.Category -eq "Already Downloaded" } + foreach ($m in $dlModels) { + $padNum = $m.Num.ToString().PadLeft(2) + Write-Host " [$padNum]" -ForegroundColor Yellow -NoNewline + Write-Host " $($m.Name.PadRight(24))" -ForegroundColor White -NoNewline + Write-Host ("[" + $m.Input + "]").PadRight(16) -ForegroundColor DarkCyan -NoNewline + Write-Host " (~$($m.Size) GB)".PadRight(12) -ForegroundColor DarkGray -NoNewline + Write-Host " [DOWNLOADED]" -ForegroundColor Green + } +} + +Write-Host "`n [C] CUSTOM - Enter an Official Ollama Tag" -ForegroundColor Green +Write-Host " Browse ALL models here: " -ForegroundColor Gray -NoNewline +Write-Host "https://ollama.com/library" -ForegroundColor Blue +Write-Host "`n ------------------------------------------------" -ForegroundColor DarkGray +Write-Host " Enter number(s) separated by commas (e.g. 1,4)" -ForegroundColor Gray +Write-Host " Type 'all' for every preset model, 'c' for custom`n" -ForegroundColor Gray + +$UserChoice = Read-Host " Your choice" +if ([string]::IsNullOrWhiteSpace($UserChoice)) { + Write-Host "`n No input! Defaulting to [3] Gemma 4 E4B..." -ForegroundColor Yellow + $UserChoice = "3" +} + +$SelectedModels = @() +$HasCustom = $false + +if ($UserChoice.Trim().ToLower() -eq "all") { $SelectedModels = @($ModelCatalog) } +else { + foreach ($t in ($UserChoice -split "," | ForEach-Object { $_.Trim().ToLower() })) { + if ($t -eq "c" -or $t -eq "custom") { $HasCustom = $true } + elseif ($t -match '^\d+$') { + $num = [int]$t + $found = $ModelCatalog | Where-Object { $_.Num -eq $num } + if ($found -and -Not ($SelectedModels | Where-Object { $_.Num -eq $num })) { $SelectedModels += $found } + } + } +} + +if ($HasCustom) { + Write-Host "`n ---- Custom Model Setup ----" -ForegroundColor Green + $customTag = Read-Host " Ollama Tag (e.g. mistral-nemo, phi3)" + if ($customTag) { + $customName = (CultureInfo.CurrentCulture.TextInfo.ToTitleCase($customTag.ToLower())) + $SelectedModels += @{ Num=99; Name="Custom: $customName"; Tag=$customTag.Trim(); Size="?"; Label="CUSTOM" } + Write-Host " Custom model added!" -ForegroundColor Green + } +} + +if ($SelectedModels.Count -eq 0) { Write-Host "`n ERROR: No models selected!" -ForegroundColor Red; exit 1 } + +$totalSizeGB = 0 +foreach ($m in $SelectedModels) { + if ($m.Size -match '\d') { $totalSizeGB += [double]$m.Size } +} + +if ($totalSizeGB -ge ($freeGB - 1) -and $freeGB -gt 0 -or $UserChoice.Trim().ToLower() -eq "all") { + Write-Host "`n WARNING: These models total ~$([math]::Ceiling($totalSizeGB)) GB. USB drive has $freeGB GB free!" -ForegroundColor Red + $confirm = Read-Host " Continue? (yes/no)" + if ($confirm.Trim().ToLower() -ne "yes" -and $confirm.Trim().ToLower() -ne "y") { exit } +} + +# Directories +New-Item -ItemType Directory -Force -Path $ModelsDir | Out-Null +New-Item -ItemType Directory -Force -Path "$OllamaDir\data" | Out-Null +Write-Host "`n[2/4] Created storage folders." -ForegroundColor Green + +# Ollama Engine Setup +Write-Host "`n[3/4] Setting up Portable Ollama Engine..." -ForegroundColor Yellow +$OllamaURL = "https://github.com/ollama/ollama/releases/latest/download/ollama-windows-amd64.zip" +$OllamaDest = "$OllamaDir\ollama.zip" +$OllamaExe = "$OllamaDir\ollama.exe" + +if (Test-Path $OllamaExe) { + Write-Host " Engine already installed!" -ForegroundColor Green +} else { + Write-Host " Downloading Ollama Engine (~100MB)..." -ForegroundColor Yellow + curl.exe -L --ssl-no-revoke $OllamaURL -o $OllamaDest + if (Test-Path $OllamaDest) { + Write-Host " Extracting to USB..." -ForegroundColor Yellow + Expand-Archive -Path $OllamaDest -DestinationPath $OllamaDir -Force + Remove-Item $OllamaDest -Force -ErrorAction SilentlyContinue + Write-Host " Engine Installed successfully!" -ForegroundColor Green + } else { + Write-Host " ERROR: Failed to download engine!" -ForegroundColor Red + exit 1 + } +} + +# Downloading Models via Ollama +Write-Host "`n[4/4] Pulling Models (This guarantees perfectly configured Tool Support)..." -ForegroundColor Yellow + +$downloadErrors = @() + +$env:OLLAMA_MODELS = "$OllamaDir\data" +Write-Host "`n Starting background Ollama server on USB..." -ForegroundColor DarkGray +$ServerProcess = Start-Process -FilePath $OllamaExe -ArgumentList "serve" -WindowStyle Hidden -PassThru +Start-Sleep -Seconds 5 + +$idx = 1 +foreach ($m in $SelectedModels) { + if ($m.Tag -match "^http.*" -and $m.Tag -match "\.gguf") { + $tagUrlNoQuery = $m.Tag.Split('?')[0] + $fileName = $tagUrlNoQuery.Split('/')[-1] + if (-not $fileName.EndsWith(".gguf")) { $fileName += ".gguf" } + $dest = "$ModelsDir\$fileName" + + $baseName = $fileName -ireplace '\.gguf$', '' + $modelNameLocal = "$baseName-local".ToLower() -replace '[^a-z0-9_-]', '-' + + # --- Always verify real file size against server --- + Write-Host "`n ($idx/$($SelectedModels.Count)) Checking $($m.Name)..." -ForegroundColor Yellow + $idx++ + + $expectedSize = 0 + $existingSize = 0 + try { + $headResponse = Invoke-WebRequest -Uri $m.Tag -Method Head -UseBasicParsing -ErrorAction Stop + $expectedSize = [long]$headResponse.Headers['Content-Length'] + } catch {} + if (Test-Path $dest) { $existingSize = (Get-Item $dest).Length } + + $fileComplete = ($expectedSize -gt 0 -and $existingSize -ge $expectedSize) + + # Only skip if file is FULLY downloaded AND ollama has it imported + $showResult = & $OllamaExe show $modelNameLocal 2>&1 + if ($fileComplete -and $LASTEXITCODE -eq 0) { + $existMegabytes = [math]::Round($existingSize / 1MB) + Write-Host (" $([char]0x2705) {0} fully downloaded ({1} MB) & imported - skipping!" -f $m.Name, $existMegabytes) -ForegroundColor Green + $m.Tag = $modelNameLocal + continue + } + + Write-Host " Do not close this window! Download may take a while." -ForegroundColor Magenta + + try { + # --- Download or resume --- + if ((Test-Path $dest) -and -not $fileComplete) { + $existMegabytes = [math]::Round($existingSize / 1MB) + $expectMegabytes = [math]::Round($expectedSize / 1MB) + Write-Host (" {0} is incomplete ({1} MB / {2} MB). Resuming..." -f $fileName, $existMegabytes, $expectMegabytes) -ForegroundColor Yellow + curl.exe -L -C - $($m.Tag) -o $dest + } elseif (-not $fileComplete) { + Write-Host " Downloading $fileName (speed + ETA shown below)..." -ForegroundColor Cyan + curl.exe -L -C - $($m.Tag) -o $dest + } + + $modelFileContent = "FROM ./$fileName`nPARAMETER temperature 0.7`nPARAMETER top_p 0.9" + $modelFilePath = "$ModelsDir\Modelfile-$modelNameLocal" + Set-Content -Path $modelFilePath -Value $modelFileContent -Encoding Ascii + + Write-Host " Importing into Ollama as '$modelNameLocal'..." -ForegroundColor Cyan + Push-Location $ModelsDir + $createArgs = "create $modelNameLocal -f Modelfile-$modelNameLocal" + $createProcess = Start-Process -FilePath $OllamaExe -ArgumentList $createArgs -Wait -NoNewWindow -PassThru + Pop-Location + + if ($createProcess.ExitCode -eq 0) { + Write-Host " Import complete!" -ForegroundColor Green + $m.Tag = $modelNameLocal + } else { + throw "Exit code $($createProcess.ExitCode)" + } + } catch { + Write-Host " FAILED to import custom model: $fileName" -ForegroundColor Red + $downloadErrors += $m.Name + } + continue + } + + # --- Check if standard Ollama model already exists --- + $showResult = & $OllamaExe show $($m.Tag) 2>&1 + if ($LASTEXITCODE -eq 0) { + Write-Host "`n ($idx/$($SelectedModels.Count)) " -ForegroundColor Green -NoNewline + Write-Host ("$([char]0x2705) {0} [{1}] already pulled - skipping!" -f $m.Name, $m.Tag) -ForegroundColor Green + $idx++ + continue + } + + Write-Host "`n ($idx/$($SelectedModels.Count)) Pulling $($m.Name) [$($m.Tag)]..." -ForegroundColor Yellow + Write-Host " Do not close this window! Download may take a while depending on bandwidth." -ForegroundColor Magenta + $idx++ + + try { + $pullArgs = "pull $($m.Tag)" + $pullProcess = Start-Process -FilePath $OllamaExe -ArgumentList $pullArgs -Wait -NoNewWindow -PassThru + if ($pullProcess.ExitCode -ne 0) { throw "Exit code $($pullProcess.ExitCode)" } + Write-Host " Pull complete!" -ForegroundColor Green + } catch { + Write-Host " FAILED to pull model: $($m.Tag)" -ForegroundColor Red + $downloadErrors += $m.Name + } +} + +Write-Host "`n Stopping background Ollama server..." -ForegroundColor DarkGray +Stop-Process -Id $ServerProcess.Id -Force -ErrorAction SilentlyContinue + +# Record Models for the Dashboard +$installedList = $SelectedModels | ForEach-Object { "$($_.Tag)|$($_.Name)|$($_.Label)" } +if (Test-Path "$ModelsDir\installed-models.txt") { + $existing = Get-Content "$ModelsDir\installed-models.txt" + $installedList = ($existing + $installedList) | Select-Object -Unique +} +Set-Content -Path "$ModelsDir\installed-models.txt" -Value ($installedList -join "`n") -Force -Encoding UTF8 + +Write-Host "`n[5/5] Finalizing Configurations..." -ForegroundColor Yellow + +$firstModelTag = $SelectedModels[0].Tag +$configContent = "AI_PROVIDER=ollama`nCLAUDE_CODE_USE_OPENAI=1`nOPENAI_API_KEY=ollama`nOPENAI_BASE_URL=http://localhost:11434/v1`nOPENAI_MODEL=$firstModelTag`nAI_DISPLAY_MODEL=$firstModelTag" +Set-Content -Path $EnvFile -Value $configContent -Force -Encoding Ascii +Write-Host " Default Model set to: $firstModelTag" -ForegroundColor Green + +Write-Host "`n==========================================================" -ForegroundColor Cyan +if ($downloadErrors.Count -gt 0) { Write-Host " SETUP COMPLETE (with some download errors)" -ForegroundColor Yellow } +else { Write-Host " SETUP COMPLETE! LOCAL AI AGENTS ARE READY!" -ForegroundColor Green } +Write-Host "==========================================================" -ForegroundColor Cyan From 5a31f8f8296b79ffc290e5dec1992e3304968b06 Mon Sep 17 00:00:00 2001 From: Rainman74 Date: Mon, 18 May 2026 18:39:45 +0200 Subject: [PATCH 2/6] Improved logic --- RESUME - Kopie.bat | 191 +++++++++++++++++++++++++++++++++++++++++ RESUME.bat | 209 ++++++++++++++++++++++++++------------------- 2 files changed, 314 insertions(+), 86 deletions(-) create mode 100644 RESUME - Kopie.bat diff --git a/RESUME - Kopie.bat b/RESUME - Kopie.bat new file mode 100644 index 0000000..1d4d725 --- /dev/null +++ b/RESUME - Kopie.bat @@ -0,0 +1,191 @@ +@echo off & setlocal enabledelayedexpansion +chcp 65001 >nul +title OpenClaude - Resume Last Session +goto :INIT + +:INIT +set "ENGINE_DIR=%~dp0engine\" +set "USB_ROOT=%ENGINE_DIR%..\" +set "DATA_DIR=%USB_ROOT%data" +set "ENV_FILE=%DATA_DIR%\ai_settings.env" +set "NODE_DIR=%ENGINE_DIR%node-win-x64" +set "GIT_DIR=%ENGINE_DIR%git-win-x64" +set "GIT_BASH=%GIT_DIR%\bin\bash.exe" +set "GIT_EXE=%GIT_DIR%\bin\git.exe" +set "OC_BIN=%ENGINE_DIR%node_modules\@gitlawb\openclaude\bin\openclaude" + +set "CLAUDE_CONFIG_DIR=%DATA_DIR%\openclaude" +set "PORTABLE_HOME=%DATA_DIR%\home" +set "XDG_CONFIG_HOME=%DATA_DIR%\config" +set "XDG_DATA_HOME=%DATA_DIR%\app_data" +set "XDG_CACHE_HOME=%DATA_DIR%\cache" +set "APPDATA=%DATA_DIR%\app_data" +set "LOCALAPPDATA=%DATA_DIR%\local_app_data" +set "HOME=%PORTABLE_HOME%" +set "USERPROFILE=%PORTABLE_HOME%" + +set "PATH=%NODE_DIR%;%GIT_DIR%\cmd;%GIT_DIR%\bin;%GIT_DIR%\usr\bin;%PATH%" +set "CLAUDE_CODE_GIT_BASH_PATH=%GIT_BASH%" +goto :MAIN + +:MAIN +if not exist "%NODE_DIR%\node.exe" ( + echo [ERROR] Node.js was not found: %NODE_DIR%\node.exe + echo Please run START.bat first. + pause + exit /b 1 +) + +if not exist "%GIT_BASH%" ( + echo [ERROR] Git Bash was not found: %GIT_BASH% + echo Please run START.bat first. + pause + exit /b 1 +) + +if not exist "%GIT_EXE%" ( + echo [ERROR] Git executable was not found: %GIT_EXE% + echo Please run START.bat first. + pause + exit /b 1 +) + +if not exist "%OC_BIN%" ( + echo [ERROR] OpenClaude was not found: %OC_BIN% + echo Please run START.bat first. + pause + exit /b 1 +) + +if exist "%ENV_FILE%" ( + for /f "usebackq tokens=1,* delims==" %%A in ("%ENV_FILE%") do ( + set "%%A=%%~B" + ) +) else ( + echo [WARN] No provider configuration found: %ENV_FILE% +) + +if not "!AI_PROVIDER!" == "anthropic" ( + set "ANTHROPIC_API_KEY=" +) + +set "SESSION_ID=" +set "WORK_DIR=" + +if "%~1" == "" goto ARGS_DONE + +if /i "%~1" == "--cwd" ( + set "WORK_DIR=%~2" + goto ARGS_DONE +) + +if /i "%~1" == "--resume" ( + set "SESSION_ID=%~2" + if /i "%~3" == "--cwd" ( + set "WORK_DIR=%~4" + ) else ( + set "WORK_DIR=%~3" + ) + goto ARGS_DONE +) + +if exist "%~1\" ( + set "WORK_DIR=%~1" + goto ARGS_DONE +) + +set "SESSION_ID=%~1" +if /i "%~2" == "--cwd" ( + set "WORK_DIR=%~3" +) else ( + set "WORK_DIR=%~2" +) + +:ARGS_DONE +if /i "%~1" == "--resume" ( + if not defined SESSION_ID ( + echo [ERROR] No session ID provided after --resume. + pause + exit /b 1 + ) +) +if /i "%~1" == "--cwd" ( + if not defined WORK_DIR ( + echo [ERROR] No working directory provided after --cwd. + pause + exit /b 1 + ) +) +if /i "%~2" == "--cwd" ( + if not defined WORK_DIR ( + echo [ERROR] No working directory provided after --cwd. + pause + exit /b 1 + ) +) +if /i "%~3" == "--cwd" ( + if not defined WORK_DIR ( + echo [ERROR] No working directory provided after --cwd. + pause + exit /b 1 + ) +) +if not defined WORK_DIR set "WORK_DIR=%ENGINE_DIR%" + +if not exist "!WORK_DIR!\" ( + echo [ERROR] Working directory was not found: !WORK_DIR! + pause + exit /b 1 +) + +set "PROVIDER_ARGS=" +if defined AI_PROVIDER set "PROVIDER_ARGS=--provider !AI_PROVIDER!" +set "CMD_ARGS=--dangerously-skip-permissions" + +if not "!AI_PROVIDER!" == "ollama" goto SKIP_OLLAMA_START +if not exist "%DATA_DIR%\ollama\ollama.exe" goto SKIP_OLLAMA_START + +echo [~] Starting Local Ollama Server... +set "OLLAMA_MODELS=%DATA_DIR%\ollama\data" +start "Ollama Portable" /b /min "%DATA_DIR%\ollama\ollama.exe" serve >nul 2>&1 +timeout /t 3 /nobreak >nul +echo [OK] Ollama running! +if not exist "%USB_ROOT%tools\local-proxy.js" goto SKIP_PROXY_START +echo [~] Starting local speed proxy... +powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'Name = ''node.exe''' | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 +start "LocalProxy" /b /min "%NODE_DIR%\node.exe" "%USB_ROOT%tools\local-proxy.js" +timeout /t 2 /nobreak >nul +set "OPENAI_BASE_URL=http://localhost:11435/v1" +echo [OK] Speed proxy active. +:SKIP_PROXY_START + +:SKIP_OLLAMA_START + +pushd "!WORK_DIR!" +if defined SESSION_ID ( + call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --resume "!SESSION_ID!" + set "OC_STATUS=!ERRORLEVEL!" +) else ( + call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --continue + set "OC_STATUS=!ERRORLEVEL!" + if not "!OC_STATUS!" == "0" ( + echo [WARN] No conversation found to continue. Starting a new session in the current working directory... + call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! + set "OC_STATUS=!ERRORLEVEL!" + ) +) +popd + +if not "!AI_PROVIDER!" == "ollama" goto SKIP_OLLAMA_STOP +if not exist "%DATA_DIR%\ollama\ollama.exe" goto SKIP_OLLAMA_STOP +echo. +echo [~] Stopping Local Ollama Server... +taskkill /f /im ollama.exe >nul 2>&1 +powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'Name = ''node.exe''' | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 +:SKIP_OLLAMA_STOP + +pause +goto :END + +:END +exit /b !OC_STATUS! diff --git a/RESUME.bat b/RESUME.bat index 1d4d725..740eee4 100644 --- a/RESUME.bat +++ b/RESUME.bat @@ -8,11 +8,11 @@ set "ENGINE_DIR=%~dp0engine\" set "USB_ROOT=%ENGINE_DIR%..\" set "DATA_DIR=%USB_ROOT%data" set "ENV_FILE=%DATA_DIR%\ai_settings.env" -set "NODE_DIR=%ENGINE_DIR%node-win-x64" -set "GIT_DIR=%ENGINE_DIR%git-win-x64" +set "NODE_DIR=%ENGINE_DIR%\node-win-x64" +set "GIT_DIR=%ENGINE_DIR%\git-win-x64" set "GIT_BASH=%GIT_DIR%\bin\bash.exe" set "GIT_EXE=%GIT_DIR%\bin\git.exe" -set "OC_BIN=%ENGINE_DIR%node_modules\@gitlawb\openclaude\bin\openclaude" +set "OC_BIN=%ENGINE_DIR%\node_modules\@gitlawb\openclaude\bin\openclaude" set "CLAUDE_CONFIG_DIR=%DATA_DIR%\openclaude" set "PORTABLE_HOME=%DATA_DIR%\home" @@ -26,33 +26,30 @@ set "USERPROFILE=%PORTABLE_HOME%" set "PATH=%NODE_DIR%;%GIT_DIR%\cmd;%GIT_DIR%\bin;%GIT_DIR%\usr\bin;%PATH%" set "CLAUDE_CODE_GIT_BASH_PATH=%GIT_BASH%" + goto :MAIN :MAIN if not exist "%NODE_DIR%\node.exe" ( echo [ERROR] Node.js was not found: %NODE_DIR%\node.exe - echo Please run START.bat first. pause exit /b 1 ) if not exist "%GIT_BASH%" ( echo [ERROR] Git Bash was not found: %GIT_BASH% - echo Please run START.bat first. pause exit /b 1 ) if not exist "%GIT_EXE%" ( echo [ERROR] Git executable was not found: %GIT_EXE% - echo Please run START.bat first. pause exit /b 1 ) if not exist "%OC_BIN%" ( echo [ERROR] OpenClaude was not found: %OC_BIN% - echo Please run START.bat first. pause exit /b 1 ) @@ -61,131 +58,171 @@ if exist "%ENV_FILE%" ( for /f "usebackq tokens=1,* delims==" %%A in ("%ENV_FILE%") do ( set "%%A=%%~B" ) -) else ( - echo [WARN] No provider configuration found: %ENV_FILE% ) -if not "!AI_PROVIDER!" == "anthropic" ( +if /i not "!AI_PROVIDER!"=="anthropic" ( set "ANTHROPIC_API_KEY=" ) set "SESSION_ID=" set "WORK_DIR=" +set "RESUME_DEFINED=" +set "CWD_DEFINED=" -if "%~1" == "" goto ARGS_DONE +:PARSE_ARGS +if "%~1"=="" goto ARGS_DONE -if /i "%~1" == "--cwd" ( - set "WORK_DIR=%~2" - goto ARGS_DONE -) +if /i "%~1"=="--resume" ( + if defined RESUME_DEFINED ( + echo [ERROR] Duplicate --resume parameter. + pause + exit /b 1 + ) -if /i "%~1" == "--resume" ( - set "SESSION_ID=%~2" - if /i "%~3" == "--cwd" ( - set "WORK_DIR=%~4" - ) else ( - set "WORK_DIR=%~3" + if "%~2"=="" ( + echo [ERROR] Missing session ID after --resume. + pause + exit /b 1 ) - goto ARGS_DONE -) -if exist "%~1\" ( - set "WORK_DIR=%~1" - goto ARGS_DONE -) + if /i "%~2:~0,2%"=="--" ( + echo [ERROR] Invalid session ID: %~2 + pause + exit /b 1 + ) -set "SESSION_ID=%~1" -if /i "%~2" == "--cwd" ( - set "WORK_DIR=%~3" -) else ( - set "WORK_DIR=%~2" -) + set "SESSION_ID=%~2" + set "RESUME_DEFINED=1" -:ARGS_DONE -if /i "%~1" == "--resume" ( - if not defined SESSION_ID ( - echo [ERROR] No session ID provided after --resume. + echo(%SESSION_ID%| findstr /r /c:"^[A-Za-z0-9._-][A-Za-z0-9._-]*$" >nul + if errorlevel 1 ( + echo [ERROR] Invalid session ID format: %SESSION_ID% pause exit /b 1 ) + + shift + shift + goto PARSE_ARGS ) -if /i "%~1" == "--cwd" ( - if not defined WORK_DIR ( - echo [ERROR] No working directory provided after --cwd. + +if /i "%~1"=="--cwd" ( + if defined CWD_DEFINED ( + echo [ERROR] Duplicate --cwd parameter. pause exit /b 1 ) -) -if /i "%~2" == "--cwd" ( - if not defined WORK_DIR ( - echo [ERROR] No working directory provided after --cwd. + + if "%~2"=="" ( + echo [ERROR] Missing working directory after --cwd. pause exit /b 1 ) -) -if /i "%~3" == "--cwd" ( - if not defined WORK_DIR ( - echo [ERROR] No working directory provided after --cwd. + + if /i "%~2:~0,2%"=="--" ( + echo [ERROR] Invalid working directory: %~2 pause exit /b 1 ) + + set "WORK_DIR=%~2" + set "CWD_DEFINED=1" + + shift + shift + goto PARSE_ARGS ) -if not defined WORK_DIR set "WORK_DIR=%ENGINE_DIR%" -if not exist "!WORK_DIR!\" ( - echo [ERROR] Working directory was not found: !WORK_DIR! +echo [ERROR] Unknown argument: %~1 +pause +exit /b 1 + +:ARGS_DONE +if not defined WORK_DIR ( + set "WORK_DIR=%ENGINE_DIR%" +) + +if "%WORK_DIR%"=="" ( + echo [ERROR] Working directory is empty. + pause + exit /b 1 +) + +if not exist "%WORK_DIR%\" ( + echo [ERROR] Working directory not found: %WORK_DIR% pause exit /b 1 ) set "PROVIDER_ARGS=" -if defined AI_PROVIDER set "PROVIDER_ARGS=--provider !AI_PROVIDER!" +if defined AI_PROVIDER ( + set "PROVIDER_ARGS=--provider !AI_PROVIDER!" +) + set "CMD_ARGS=--dangerously-skip-permissions" -if not "!AI_PROVIDER!" == "ollama" goto SKIP_OLLAMA_START -if not exist "%DATA_DIR%\ollama\ollama.exe" goto SKIP_OLLAMA_START - -echo [~] Starting Local Ollama Server... -set "OLLAMA_MODELS=%DATA_DIR%\ollama\data" -start "Ollama Portable" /b /min "%DATA_DIR%\ollama\ollama.exe" serve >nul 2>&1 -timeout /t 3 /nobreak >nul -echo [OK] Ollama running! -if not exist "%USB_ROOT%tools\local-proxy.js" goto SKIP_PROXY_START -echo [~] Starting local speed proxy... -powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'Name = ''node.exe''' | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 -start "LocalProxy" /b /min "%NODE_DIR%\node.exe" "%USB_ROOT%tools\local-proxy.js" -timeout /t 2 /nobreak >nul -set "OPENAI_BASE_URL=http://localhost:11435/v1" -echo [OK] Speed proxy active. -:SKIP_PROXY_START - -:SKIP_OLLAMA_START - -pushd "!WORK_DIR!" +if /i "!AI_PROVIDER!"=="ollama" ( + if exist "%DATA_DIR%\ollama\ollama.exe" ( + echo [~] Starting Local Ollama Server... + set "OLLAMA_MODELS=%DATA_DIR%\ollama\data" + + start "Ollama Portable" /b /min "%DATA_DIR%\ollama\ollama.exe" serve >nul 2>&1 + + timeout /t 3 /nobreak >nul + + echo [OK] Ollama running! + + if exist "%USB_ROOT%tools\local-proxy.js" ( + echo [~] Starting local speed proxy... + + powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter \"Name = 'node.exe'\" | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 + + start "LocalProxy" /b /min "%NODE_DIR%\node.exe" "%USB_ROOT%tools\local-proxy.js" + + timeout /t 2 /nobreak >nul + + set "OPENAI_BASE_URL=http://localhost:11435/v1" + + echo [OK] Speed proxy active. + ) + ) +) + +pushd "%WORK_DIR%" >nul 2>&1 +if errorlevel 1 ( + echo [ERROR] Failed to enter working directory: %WORK_DIR% + pause + exit /b 1 +) + if defined SESSION_ID ( - call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --resume "!SESSION_ID!" + call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --resume "%SESSION_ID%" set "OC_STATUS=!ERRORLEVEL!" ) else ( call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --continue set "OC_STATUS=!ERRORLEVEL!" - if not "!OC_STATUS!" == "0" ( - echo [WARN] No conversation found to continue. Starting a new session in the current working directory... + + if not "!OC_STATUS!"=="0" ( + echo [WARN] No conversation found to continue. Starting a new session... + call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! + set "OC_STATUS=!ERRORLEVEL!" ) ) + popd -if not "!AI_PROVIDER!" == "ollama" goto SKIP_OLLAMA_STOP -if not exist "%DATA_DIR%\ollama\ollama.exe" goto SKIP_OLLAMA_STOP -echo. -echo [~] Stopping Local Ollama Server... -taskkill /f /im ollama.exe >nul 2>&1 -powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'Name = ''node.exe''' | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 -:SKIP_OLLAMA_STOP +if /i "!AI_PROVIDER!"=="ollama" ( + if exist "%DATA_DIR%\ollama\ollama.exe" ( + echo. + echo [~] Stopping Local Ollama Server... -pause -goto :END + taskkill /f /im ollama.exe >nul 2>&1 -:END -exit /b !OC_STATUS! + powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter \"Name = 'node.exe'\" | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 + ) +) + +pause +exit /b %OC_STATUS% From 6eb9aede58cd177d59160b2e6c413edc9a189281 Mon Sep 17 00:00:00 2001 From: Rainman74 Date: Mon, 18 May 2026 18:40:48 +0200 Subject: [PATCH 3/6] Improved logic --- RESUME - Kopie.bat | 191 --------------------------------------------- 1 file changed, 191 deletions(-) delete mode 100644 RESUME - Kopie.bat diff --git a/RESUME - Kopie.bat b/RESUME - Kopie.bat deleted file mode 100644 index 1d4d725..0000000 --- a/RESUME - Kopie.bat +++ /dev/null @@ -1,191 +0,0 @@ -@echo off & setlocal enabledelayedexpansion -chcp 65001 >nul -title OpenClaude - Resume Last Session -goto :INIT - -:INIT -set "ENGINE_DIR=%~dp0engine\" -set "USB_ROOT=%ENGINE_DIR%..\" -set "DATA_DIR=%USB_ROOT%data" -set "ENV_FILE=%DATA_DIR%\ai_settings.env" -set "NODE_DIR=%ENGINE_DIR%node-win-x64" -set "GIT_DIR=%ENGINE_DIR%git-win-x64" -set "GIT_BASH=%GIT_DIR%\bin\bash.exe" -set "GIT_EXE=%GIT_DIR%\bin\git.exe" -set "OC_BIN=%ENGINE_DIR%node_modules\@gitlawb\openclaude\bin\openclaude" - -set "CLAUDE_CONFIG_DIR=%DATA_DIR%\openclaude" -set "PORTABLE_HOME=%DATA_DIR%\home" -set "XDG_CONFIG_HOME=%DATA_DIR%\config" -set "XDG_DATA_HOME=%DATA_DIR%\app_data" -set "XDG_CACHE_HOME=%DATA_DIR%\cache" -set "APPDATA=%DATA_DIR%\app_data" -set "LOCALAPPDATA=%DATA_DIR%\local_app_data" -set "HOME=%PORTABLE_HOME%" -set "USERPROFILE=%PORTABLE_HOME%" - -set "PATH=%NODE_DIR%;%GIT_DIR%\cmd;%GIT_DIR%\bin;%GIT_DIR%\usr\bin;%PATH%" -set "CLAUDE_CODE_GIT_BASH_PATH=%GIT_BASH%" -goto :MAIN - -:MAIN -if not exist "%NODE_DIR%\node.exe" ( - echo [ERROR] Node.js was not found: %NODE_DIR%\node.exe - echo Please run START.bat first. - pause - exit /b 1 -) - -if not exist "%GIT_BASH%" ( - echo [ERROR] Git Bash was not found: %GIT_BASH% - echo Please run START.bat first. - pause - exit /b 1 -) - -if not exist "%GIT_EXE%" ( - echo [ERROR] Git executable was not found: %GIT_EXE% - echo Please run START.bat first. - pause - exit /b 1 -) - -if not exist "%OC_BIN%" ( - echo [ERROR] OpenClaude was not found: %OC_BIN% - echo Please run START.bat first. - pause - exit /b 1 -) - -if exist "%ENV_FILE%" ( - for /f "usebackq tokens=1,* delims==" %%A in ("%ENV_FILE%") do ( - set "%%A=%%~B" - ) -) else ( - echo [WARN] No provider configuration found: %ENV_FILE% -) - -if not "!AI_PROVIDER!" == "anthropic" ( - set "ANTHROPIC_API_KEY=" -) - -set "SESSION_ID=" -set "WORK_DIR=" - -if "%~1" == "" goto ARGS_DONE - -if /i "%~1" == "--cwd" ( - set "WORK_DIR=%~2" - goto ARGS_DONE -) - -if /i "%~1" == "--resume" ( - set "SESSION_ID=%~2" - if /i "%~3" == "--cwd" ( - set "WORK_DIR=%~4" - ) else ( - set "WORK_DIR=%~3" - ) - goto ARGS_DONE -) - -if exist "%~1\" ( - set "WORK_DIR=%~1" - goto ARGS_DONE -) - -set "SESSION_ID=%~1" -if /i "%~2" == "--cwd" ( - set "WORK_DIR=%~3" -) else ( - set "WORK_DIR=%~2" -) - -:ARGS_DONE -if /i "%~1" == "--resume" ( - if not defined SESSION_ID ( - echo [ERROR] No session ID provided after --resume. - pause - exit /b 1 - ) -) -if /i "%~1" == "--cwd" ( - if not defined WORK_DIR ( - echo [ERROR] No working directory provided after --cwd. - pause - exit /b 1 - ) -) -if /i "%~2" == "--cwd" ( - if not defined WORK_DIR ( - echo [ERROR] No working directory provided after --cwd. - pause - exit /b 1 - ) -) -if /i "%~3" == "--cwd" ( - if not defined WORK_DIR ( - echo [ERROR] No working directory provided after --cwd. - pause - exit /b 1 - ) -) -if not defined WORK_DIR set "WORK_DIR=%ENGINE_DIR%" - -if not exist "!WORK_DIR!\" ( - echo [ERROR] Working directory was not found: !WORK_DIR! - pause - exit /b 1 -) - -set "PROVIDER_ARGS=" -if defined AI_PROVIDER set "PROVIDER_ARGS=--provider !AI_PROVIDER!" -set "CMD_ARGS=--dangerously-skip-permissions" - -if not "!AI_PROVIDER!" == "ollama" goto SKIP_OLLAMA_START -if not exist "%DATA_DIR%\ollama\ollama.exe" goto SKIP_OLLAMA_START - -echo [~] Starting Local Ollama Server... -set "OLLAMA_MODELS=%DATA_DIR%\ollama\data" -start "Ollama Portable" /b /min "%DATA_DIR%\ollama\ollama.exe" serve >nul 2>&1 -timeout /t 3 /nobreak >nul -echo [OK] Ollama running! -if not exist "%USB_ROOT%tools\local-proxy.js" goto SKIP_PROXY_START -echo [~] Starting local speed proxy... -powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'Name = ''node.exe''' | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 -start "LocalProxy" /b /min "%NODE_DIR%\node.exe" "%USB_ROOT%tools\local-proxy.js" -timeout /t 2 /nobreak >nul -set "OPENAI_BASE_URL=http://localhost:11435/v1" -echo [OK] Speed proxy active. -:SKIP_PROXY_START - -:SKIP_OLLAMA_START - -pushd "!WORK_DIR!" -if defined SESSION_ID ( - call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --resume "!SESSION_ID!" - set "OC_STATUS=!ERRORLEVEL!" -) else ( - call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --continue - set "OC_STATUS=!ERRORLEVEL!" - if not "!OC_STATUS!" == "0" ( - echo [WARN] No conversation found to continue. Starting a new session in the current working directory... - call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! - set "OC_STATUS=!ERRORLEVEL!" - ) -) -popd - -if not "!AI_PROVIDER!" == "ollama" goto SKIP_OLLAMA_STOP -if not exist "%DATA_DIR%\ollama\ollama.exe" goto SKIP_OLLAMA_STOP -echo. -echo [~] Stopping Local Ollama Server... -taskkill /f /im ollama.exe >nul 2>&1 -powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 'Name = ''node.exe''' | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 -:SKIP_OLLAMA_STOP - -pause -goto :END - -:END -exit /b !OC_STATUS! From 109e61239a51d5cbc93faf2fed155c7a64470610 Mon Sep 17 00:00:00 2001 From: Rainman74 Date: Mon, 18 May 2026 18:45:26 +0200 Subject: [PATCH 4/6] Fixed bugs --- RESUME.bat | 57 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 45 insertions(+), 12 deletions(-) diff --git a/RESUME.bat b/RESUME.bat index 740eee4..24265a2 100644 --- a/RESUME.bat +++ b/RESUME.bat @@ -1,35 +1,36 @@ -@echo off & setlocal enabledelayedexpansion +@echo off & setlocal EnableDelayedExpansion chcp 65001 >nul title OpenClaude - Resume Last Session -goto :INIT -:INIT set "ENGINE_DIR=%~dp0engine\" set "USB_ROOT=%ENGINE_DIR%..\" set "DATA_DIR=%USB_ROOT%data" set "ENV_FILE=%DATA_DIR%\ai_settings.env" + set "NODE_DIR=%ENGINE_DIR%\node-win-x64" set "GIT_DIR=%ENGINE_DIR%\git-win-x64" + set "GIT_BASH=%GIT_DIR%\bin\bash.exe" set "GIT_EXE=%GIT_DIR%\bin\git.exe" + set "OC_BIN=%ENGINE_DIR%\node_modules\@gitlawb\openclaude\bin\openclaude" set "CLAUDE_CONFIG_DIR=%DATA_DIR%\openclaude" set "PORTABLE_HOME=%DATA_DIR%\home" + set "XDG_CONFIG_HOME=%DATA_DIR%\config" set "XDG_DATA_HOME=%DATA_DIR%\app_data" set "XDG_CACHE_HOME=%DATA_DIR%\cache" + set "APPDATA=%DATA_DIR%\app_data" set "LOCALAPPDATA=%DATA_DIR%\local_app_data" + set "HOME=%PORTABLE_HOME%" set "USERPROFILE=%PORTABLE_HOME%" set "PATH=%NODE_DIR%;%GIT_DIR%\cmd;%GIT_DIR%\bin;%GIT_DIR%\usr\bin;%PATH%" set "CLAUDE_CODE_GIT_BASH_PATH=%GIT_BASH%" -goto :MAIN - -:MAIN if not exist "%NODE_DIR%\node.exe" ( echo [ERROR] Node.js was not found: %NODE_DIR%\node.exe pause @@ -91,16 +92,16 @@ if /i "%~1"=="--resume" ( exit /b 1 ) - set "SESSION_ID=%~2" - set "RESUME_DEFINED=1" - - echo(%SESSION_ID%| findstr /r /c:"^[A-Za-z0-9._-][A-Za-z0-9._-]*$" >nul + echo(%~2| findstr /r /c:"^[A-Za-z0-9._-][A-Za-z0-9._-]*$" >nul if errorlevel 1 ( - echo [ERROR] Invalid session ID format: %SESSION_ID% + echo [ERROR] Invalid session ID format: %~2 pause exit /b 1 ) + set "SESSION_ID=%~2" + set "RESUME_DEFINED=1" + shift shift goto PARSE_ARGS @@ -133,6 +134,29 @@ if /i "%~1"=="--cwd" ( goto PARSE_ARGS ) +if not defined RESUME_DEFINED ( + echo(%~1| findstr /r /c:"^[A-Za-z0-9._-][A-Za-z0-9._-]*$" >nul + if errorlevel 1 ( + echo [ERROR] Invalid positional session ID: %~1 + pause + exit /b 1 + ) + + set "SESSION_ID=%~1" + set "RESUME_DEFINED=1" + + shift + goto PARSE_ARGS +) + +if not defined CWD_DEFINED ( + set "WORK_DIR=%~1" + set "CWD_DEFINED=1" + + shift + goto PARSE_ARGS +) + echo [ERROR] Unknown argument: %~1 pause exit /b 1 @@ -155,15 +179,20 @@ if not exist "%WORK_DIR%\" ( ) set "PROVIDER_ARGS=" + if defined AI_PROVIDER ( - set "PROVIDER_ARGS=--provider !AI_PROVIDER!" + if /i "!AI_PROVIDER!"=="anthropic" set "PROVIDER_ARGS=--provider anthropic" + if /i "!AI_PROVIDER!"=="ollama" set "PROVIDER_ARGS=--provider ollama" + if /i "!AI_PROVIDER!"=="nvidia" set "PROVIDER_ARGS=--provider openai" ) set "CMD_ARGS=--dangerously-skip-permissions" if /i "!AI_PROVIDER!"=="ollama" ( if exist "%DATA_DIR%\ollama\ollama.exe" ( + echo [~] Starting Local Ollama Server... + set "OLLAMA_MODELS=%DATA_DIR%\ollama\data" start "Ollama Portable" /b /min "%DATA_DIR%\ollama\ollama.exe" serve >nul 2>&1 @@ -173,6 +202,7 @@ if /i "!AI_PROVIDER!"=="ollama" ( echo [OK] Ollama running! if exist "%USB_ROOT%tools\local-proxy.js" ( + echo [~] Starting local speed proxy... powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter \"Name = 'node.exe'\" | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 @@ -189,6 +219,7 @@ if /i "!AI_PROVIDER!"=="ollama" ( ) pushd "%WORK_DIR%" >nul 2>&1 + if errorlevel 1 ( echo [ERROR] Failed to enter working directory: %WORK_DIR% pause @@ -200,6 +231,7 @@ if defined SESSION_ID ( set "OC_STATUS=!ERRORLEVEL!" ) else ( call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --continue + set "OC_STATUS=!ERRORLEVEL!" if not "!OC_STATUS!"=="0" ( @@ -215,6 +247,7 @@ popd if /i "!AI_PROVIDER!"=="ollama" ( if exist "%DATA_DIR%\ollama\ollama.exe" ( + echo. echo [~] Stopping Local Ollama Server... From de8d0271b5114b5ffb9ddc1ddd3eeda3b6d2d793 Mon Sep 17 00:00:00 2001 From: Rainman74 Date: Mon, 18 May 2026 23:40:46 +0200 Subject: [PATCH 5/6] All Codex review issues fixed --- RESUME.bat | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/RESUME.bat b/RESUME.bat index 24265a2..c72f1c1 100644 --- a/RESUME.bat +++ b/RESUME.bat @@ -6,28 +6,20 @@ set "ENGINE_DIR=%~dp0engine\" set "USB_ROOT=%ENGINE_DIR%..\" set "DATA_DIR=%USB_ROOT%data" set "ENV_FILE=%DATA_DIR%\ai_settings.env" - set "NODE_DIR=%ENGINE_DIR%\node-win-x64" set "GIT_DIR=%ENGINE_DIR%\git-win-x64" - set "GIT_BASH=%GIT_DIR%\bin\bash.exe" set "GIT_EXE=%GIT_DIR%\bin\git.exe" - set "OC_BIN=%ENGINE_DIR%\node_modules\@gitlawb\openclaude\bin\openclaude" - set "CLAUDE_CONFIG_DIR=%DATA_DIR%\openclaude" set "PORTABLE_HOME=%DATA_DIR%\home" - set "XDG_CONFIG_HOME=%DATA_DIR%\config" set "XDG_DATA_HOME=%DATA_DIR%\app_data" set "XDG_CACHE_HOME=%DATA_DIR%\cache" - set "APPDATA=%DATA_DIR%\app_data" set "LOCALAPPDATA=%DATA_DIR%\local_app_data" - set "HOME=%PORTABLE_HOME%" set "USERPROFILE=%PORTABLE_HOME%" - set "PATH=%NODE_DIR%;%GIT_DIR%\cmd;%GIT_DIR%\bin;%GIT_DIR%\usr\bin;%PATH%" set "CLAUDE_CODE_GIT_BASH_PATH=%GIT_BASH%" @@ -74,6 +66,7 @@ set "CWD_DEFINED=" if "%~1"=="" goto ARGS_DONE if /i "%~1"=="--resume" ( + if defined RESUME_DEFINED ( echo [ERROR] Duplicate --resume parameter. pause @@ -108,6 +101,7 @@ if /i "%~1"=="--resume" ( ) if /i "%~1"=="--cwd" ( + if defined CWD_DEFINED ( echo [ERROR] Duplicate --cwd parameter. pause @@ -135,6 +129,21 @@ if /i "%~1"=="--cwd" ( ) if not defined RESUME_DEFINED ( + + if exist "%~1\" ( + if defined CWD_DEFINED ( + echo [ERROR] Duplicate working directory argument. + pause + exit /b 1 + ) + + set "WORK_DIR=%~1" + set "CWD_DEFINED=1" + + shift + goto PARSE_ARGS + ) + echo(%~1| findstr /r /c:"^[A-Za-z0-9._-][A-Za-z0-9._-]*$" >nul if errorlevel 1 ( echo [ERROR] Invalid positional session ID: %~1 @@ -150,6 +159,13 @@ if not defined RESUME_DEFINED ( ) if not defined CWD_DEFINED ( + + if /i "%~1:~0,2%"=="--" ( + echo [ERROR] Unknown argument: %~1 + pause + exit /b 1 + ) + set "WORK_DIR=%~1" set "CWD_DEFINED=1" @@ -183,6 +199,7 @@ set "PROVIDER_ARGS=" if defined AI_PROVIDER ( if /i "!AI_PROVIDER!"=="anthropic" set "PROVIDER_ARGS=--provider anthropic" if /i "!AI_PROVIDER!"=="ollama" set "PROVIDER_ARGS=--provider ollama" + if /i "!AI_PROVIDER!"=="gemini" set "PROVIDER_ARGS=--provider gemini" if /i "!AI_PROVIDER!"=="nvidia" set "PROVIDER_ARGS=--provider openai" ) From af01e1f504c615702f27c741c4275f9786f161c5 Mon Sep 17 00:00:00 2001 From: Rainman74 Date: Tue, 19 May 2026 00:35:23 +0200 Subject: [PATCH 6/6] Codex review issues fixed --- RESUME.bat | 64 +++++++++++++----------------------------------------- 1 file changed, 15 insertions(+), 49 deletions(-) diff --git a/RESUME.bat b/RESUME.bat index c72f1c1..7ffdb4c 100644 --- a/RESUME.bat +++ b/RESUME.bat @@ -66,109 +66,89 @@ set "CWD_DEFINED=" if "%~1"=="" goto ARGS_DONE if /i "%~1"=="--resume" ( - if defined RESUME_DEFINED ( echo [ERROR] Duplicate --resume parameter. pause exit /b 1 ) - if "%~2"=="" ( echo [ERROR] Missing session ID after --resume. pause exit /b 1 ) - if /i "%~2:~0,2%"=="--" ( echo [ERROR] Invalid session ID: %~2 pause exit /b 1 ) - echo(%~2| findstr /r /c:"^[A-Za-z0-9._-][A-Za-z0-9._-]*$" >nul if errorlevel 1 ( echo [ERROR] Invalid session ID format: %~2 pause exit /b 1 ) - set "SESSION_ID=%~2" set "RESUME_DEFINED=1" - shift shift goto PARSE_ARGS ) if /i "%~1"=="--cwd" ( - if defined CWD_DEFINED ( echo [ERROR] Duplicate --cwd parameter. pause exit /b 1 ) - if "%~2"=="" ( echo [ERROR] Missing working directory after --cwd. pause exit /b 1 ) - if /i "%~2:~0,2%"=="--" ( echo [ERROR] Invalid working directory: %~2 pause exit /b 1 ) - set "WORK_DIR=%~2" set "CWD_DEFINED=1" - shift shift goto PARSE_ARGS ) if not defined RESUME_DEFINED ( - if exist "%~1\" ( if defined CWD_DEFINED ( echo [ERROR] Duplicate working directory argument. pause exit /b 1 ) - set "WORK_DIR=%~1" set "CWD_DEFINED=1" - shift goto PARSE_ARGS ) - echo(%~1| findstr /r /c:"^[A-Za-z0-9._-][A-Za-z0-9._-]*$" >nul if errorlevel 1 ( echo [ERROR] Invalid positional session ID: %~1 pause exit /b 1 ) - set "SESSION_ID=%~1" set "RESUME_DEFINED=1" - shift goto PARSE_ARGS ) if not defined CWD_DEFINED ( - if /i "%~1:~0,2%"=="--" ( echo [ERROR] Unknown argument: %~1 pause exit /b 1 ) - set "WORK_DIR=%~1" set "CWD_DEFINED=1" - shift goto PARSE_ARGS ) @@ -195,48 +175,41 @@ if not exist "%WORK_DIR%\" ( ) set "PROVIDER_ARGS=" - -if defined AI_PROVIDER ( - if /i "!AI_PROVIDER!"=="anthropic" set "PROVIDER_ARGS=--provider anthropic" - if /i "!AI_PROVIDER!"=="ollama" set "PROVIDER_ARGS=--provider ollama" - if /i "!AI_PROVIDER!"=="gemini" set "PROVIDER_ARGS=--provider gemini" - if /i "!AI_PROVIDER!"=="nvidia" set "PROVIDER_ARGS=--provider openai" +if /i "!AI_PROVIDER!"=="anthropic" set "PROVIDER_ARGS=--provider anthropic" +if /i "!AI_PROVIDER!"=="gemini" set "PROVIDER_ARGS=--provider gemini" +if /i "!AI_PROVIDER!"=="ollama" set "PROVIDER_ARGS=--provider ollama" +if /i "!AI_PROVIDER!"=="nvidia" set "PROVIDER_ARGS=--provider nvidia-nim" +if /i "!AI_PROVIDER!"=="openai" ( + echo !OPENAI_BASE_URL! | findstr /c:"integrate.api.nvidia.com" >nul && set "PROVIDER_ARGS=--provider nvidia-nim" ) +set "MODEL_ARGS=" +if defined OPENAI_MODEL set "MODEL_ARGS=--model !OPENAI_MODEL!" +if defined GEMINI_MODEL set "MODEL_ARGS=--model !GEMINI_MODEL!" +if defined ANTHROPIC_MODEL set "MODEL_ARGS=--model !ANTHROPIC_MODEL!" + +set "SETTINGS_ARGS=--setting-sources local" set "CMD_ARGS=--dangerously-skip-permissions" if /i "!AI_PROVIDER!"=="ollama" ( if exist "%DATA_DIR%\ollama\ollama.exe" ( - echo [~] Starting Local Ollama Server... - set "OLLAMA_MODELS=%DATA_DIR%\ollama\data" - start "Ollama Portable" /b /min "%DATA_DIR%\ollama\ollama.exe" serve >nul 2>&1 - timeout /t 3 /nobreak >nul - echo [OK] Ollama running! - if exist "%USB_ROOT%tools\local-proxy.js" ( - echo [~] Starting local speed proxy... - powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter \"Name = 'node.exe'\" | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 - start "LocalProxy" /b /min "%NODE_DIR%\node.exe" "%USB_ROOT%tools\local-proxy.js" - timeout /t 2 /nobreak >nul - set "OPENAI_BASE_URL=http://localhost:11435/v1" - echo [OK] Speed proxy active. ) ) ) pushd "%WORK_DIR%" >nul 2>&1 - if errorlevel 1 ( echo [ERROR] Failed to enter working directory: %WORK_DIR% pause @@ -244,18 +217,14 @@ if errorlevel 1 ( ) if defined SESSION_ID ( - call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --resume "%SESSION_ID%" + call "%NODE_DIR%\node.exe" "%OC_BIN%" !SETTINGS_ARGS! !PROVIDER_ARGS! !MODEL_ARGS! !CMD_ARGS! --resume "%SESSION_ID%" set "OC_STATUS=!ERRORLEVEL!" ) else ( - call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! --continue - + call "%NODE_DIR%\node.exe" "%OC_BIN%" !SETTINGS_ARGS! !PROVIDER_ARGS! !MODEL_ARGS! !CMD_ARGS! --continue set "OC_STATUS=!ERRORLEVEL!" - if not "!OC_STATUS!"=="0" ( echo [WARN] No conversation found to continue. Starting a new session... - - call "%NODE_DIR%\node.exe" "%OC_BIN%" !PROVIDER_ARGS! !CMD_ARGS! - + call "%NODE_DIR%\node.exe" "%OC_BIN%" !SETTINGS_ARGS! !PROVIDER_ARGS! !MODEL_ARGS! !CMD_ARGS! set "OC_STATUS=!ERRORLEVEL!" ) ) @@ -264,12 +233,9 @@ popd if /i "!AI_PROVIDER!"=="ollama" ( if exist "%DATA_DIR%\ollama\ollama.exe" ( - echo. echo [~] Stopping Local Ollama Server... - taskkill /f /im ollama.exe >nul 2>&1 - powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter \"Name = 'node.exe'\" | Where-Object { $_.CommandLine -like '*local-proxy.js*' } | ForEach-Object { Stop-Process -Id $_.ProcessId -Force }" >nul 2>&1 ) )