feat: add safe Javis startup script

This commit is contained in:
2026-07-30 18:09:06 +02:00
parent af9426edc4
commit 141ff2e013
6 changed files with 210 additions and 31 deletions
+26 -14
View File
@@ -4,34 +4,46 @@ Javis ist ein langfristiges, lokal-first ausgerichtetes Projekt für einen pers
## Aktueller Stand
Der erste lokale Textchat funktioniert auf Windows mit Ollama und `qwen3:8b`.
Er bietet echte lokale Modellantworten ohne Cloud-Fallback, neue und fortsetzbare
Sitzungen sowie SQLite-Persistenz außerhalb des Repositories.
Der lokale Textchat funktioniert auf Windows mit Ollama und `qwen3:8b`.
Ein optionaler Gemini-Free-Provider ist auf einem Feature-Branch vorbereitet;
Datenschutzrouter, Nullkostenmodus und lokales Fallback sind automatisiert
getestet, aber noch nicht von Pascal mit einem echten Key abgenommen.
Noch nicht implementiert sind Obsidian-Zugriff, Serverzugriff, Sprache, Mobile
Client und Living Mind.
## Lokaler Start
## Einfacher Start
Ollama läuft in einem eigenen Terminal ausschließlich auf localhost:
Aus dem Repository:
```powershell
$env:OLLAMA_MODELS = 'D:\Javis-Data\ollama-models'
$env:OLLAMA_HOST = '127.0.0.1:11434'
& 'D:\Javis-Tools\ollama\ollama.exe' serve
powershell -ExecutionPolicy Bypass -File .\scripts\start-javis.ps1
```
Der Chat startet aus dem Repository in einem zweiten Terminal:
Das Skript findet die portablen Werkzeuge standardmäßig relativ zum Laufwerk des
Repositories, setzt Variablen nur für seinen Prozess, prüft Ollama ausschließlich
auf `127.0.0.1:11434`, startet es bei Bedarf versteckt und öffnet den Chat. Es
ändert weder PATH, Registry, Autostart, Windows-Dienste noch die systemweite
PowerShell-Ausführungsrichtlinie.
```powershell
$env:UV_CACHE_DIR = 'D:\Javis-Tools\uv-cache'
$env:JAVIS_DATA_DIR = 'D:\Javis-Data\runtime'
& 'D:\Javis-Tools\uv\uv.exe' run javis chat
```
Abweichende Pfade sind über die Skriptparameter `-UvPath`, `-OllamaPath`,
`-OllamaModels`, `-DataDir`, `-UvCacheDir` und `-PythonInstallDir` oder die
entsprechenden `JAVIS_*`-Umgebungsvariablen möglich.
Im Chat zeigt `/help` alle Befehle. Ohne `JAVIS_DATA_DIR` nutzt Javis einen
sicheren benutzerspezifischen Plattformstandard.
Gemini bleibt standardmäßig aus. Die spätere lokale Einrichtung erfolgt ohne
Key in der Konfigurationsdatei:
```powershell
& 'D:\Javis-Tools\uv\uv.exe' run javis configure gemini
& 'D:\Javis-Tools\uv\uv.exe' run javis secrets set gemini
```
Der Key wird bei der zweiten Zeile verdeckt eingegeben und im
Betriebssystem-Keyring gespeichert, niemals in Git oder TOML.
## Grundregeln
- Plattformunabhängiger modularer Monolith, voraussichtlich in Python.
+11 -5
View File
@@ -95,6 +95,9 @@ Rootserver:
- Der echte CLI-Chat verwendet nun `hybrid/auto`; der Key wird erst vor einem
zulässigen Cloudaufruf gelesen. `/provider`, `/privacy` und `/status` zeigen
ausschließlich bereinigte Modi, Entscheidungen und Zähler.
- `scripts/start-javis.ps1` verifiziert das Repository, setzt nur
Prozessvariablen, prüft Ollama auf Loopback, startet es bei Bedarf versteckt
und wartet begrenzt. Pfade sind per Parameter oder `JAVIS_*` überschreibbar.
## Aktuelle Architektur
@@ -151,6 +154,8 @@ Rootserver:
- Hybridprovider in die CLI verdrahtet, sicheren Aktivierungsdialog und
bereinigte Provider-/Datenschutz-/Statusbefehle ergänzt.
- Lesender Ollama-Status prüft nur Loopback-Erreichbarkeit und Modellliste.
- Sicheres PowerShell-Startskript und kompakte Startdokumentation ergänzt; keine
PATH-, Registry-, Autostart-, Dienst- oder Richtlinienänderung.
## Aktuelle Tests
@@ -165,8 +170,8 @@ Letzter bestätigter Projektstand:
- uv-Lock und `uv sync --dev`: bestanden
- Python in `.venv`: 3.12.13
- Ruff in `.venv`: 0.16.0
- Unit-Tests: 59 bestanden; CLI-Befehle, doppelte Bestätigung, verzögertes
Key-Laden und Ollama-Status sind abgedeckt
- Unit-Tests: 60 bestanden; Startskript-Sicherheitsregeln zusätzlich abgedeckt
- PowerShell-Syntax des Startskripts: erfolgreich geparst
- Ruff Lint: bestanden
- Ruff Formatprüfung: bestanden
@@ -252,9 +257,10 @@ Abnahmestatus:
Auf dem bestehenden Feature-Branch als nächstes einzelnes Arbeitspaket:
1. sicheres `scripts/start-javis.ps1` ohne Systemänderungen ergänzen
2. Start- und Einrichtungsablauf kompakt dokumentieren und automatisiert prüfen
3. noch keine echte Cloudanfrage ausführen und noch nicht nach `main` mergen
1. geforderte Resttests ergänzen, insbesondere Timeout und bereinigte Fehler
2. vollständige Qualitäts-, Gitignore-, Secret- und Außenbereichsprüfung ausführen
3. Abschlussdokumentation aktualisieren, Feature-Branch pushen und vor Pascals
manuellem Live-Test stoppen; nicht nach `main` mergen
Keinen API-Key in Chat, Git, Obsidian, Logs oder Dokumentation übernehmen.
+18 -10
View File
@@ -35,19 +35,27 @@ $env:UV_CACHE_DIR = 'D:\Javis-Tools\uv-cache'
& 'D:\Javis-Tools\uv\uv.exe' run ruff format --check .
```
Vor dem Chat wird Ollama in einem eigenen Terminal gestartet:
## Komfortabler Start
Der normale Start aus dem Repository benötigt nur:
```powershell
$env:OLLAMA_MODELS = 'D:\Javis-Data\ollama-models'
$env:OLLAMA_HOST = '127.0.0.1:11434'
& 'D:\Javis-Tools\ollama\ollama.exe' serve
powershell -ExecutionPolicy Bypass -File .\scripts\start-javis.ps1
```
Danach:
`-ExecutionPolicy Bypass` gilt nur für diesen Prozess; das Skript ändert keine
systemweite Richtlinie. Es prüft Ollama auf Loopback, startet bei Bedarf die
portable Laufzeit versteckt und wartet höchstens 15 Sekunden. Werkzeug- und
Datenpfade können mit Parametern oder folgenden Umgebungsvariablen überschrieben
werden:
```powershell
$env:JAVIS_DATA_DIR = 'D:\Javis-Data\runtime'
& 'D:\Javis-Tools\uv\uv.exe' run javis chat
```
- `JAVIS_UV_PATH`
- `JAVIS_OLLAMA_PATH`
- `JAVIS_OLLAMA_MODELS`
- `JAVIS_DATA_DIR`
- `JAVIS_UV_CACHE_DIR`
- `JAVIS_PYTHON_INSTALL_DIR`
Die absoluten Pfade sind ausschließlich lokale Entwicklungsdokumentation. Der Anwendungscode darf keine festen Windows-Pfade enthalten.
Die Standardpfade werden vom Laufwerk des Repositorys abgeleitet; persönliche
Windows-Benutzerpfade sind nicht eingebrannt. PATH, Registry, Autostart und
Windows-Dienste bleiben unverändert.
+4 -2
View File
@@ -58,7 +58,9 @@ Stand: lokaler Textchat auf `main`, 30.07.2026.
- `javis configure gemini` mit doppelter ausdrücklicher Bestätigung
- echter Chat auf Hybridprovider verdrahtet; Key wird verzögert geladen
- `/provider`, `/privacy` und `/status` geben keine Inhalte oder Keywerte aus
- 59 Unit-Tests aktuell erfolgreich; Ruff-Format und Lint sauber
- sicheres `scripts/start-javis.ps1` mit relativer Repositoryprüfung,
Loopback-Ollama und überschreibbaren externen Pfaden
- 60 Unit-Tests aktuell erfolgreich; PowerShell-Syntax, Ruff-Format und Lint sauber
## Nicht implementiert
@@ -83,6 +85,6 @@ Living-Mind-Frontend und automatische Ollama-Prozessverwaltung.
Ollama wird bewusst manuell in einem eigenen Terminal gestartet. Antworten werden
noch nicht gestreamt; Sitzungen haben noch keine Titel, Suche oder Löschfunktion.
`qwen3:8b` ist nicht automatisch für die GTX 1050 des späteren Zielhosts geeignet.
Das sichere Startskript und die abschließende Bedienungsdokumentation fehlen noch.
Abschließende Resttests, Qualitätsprüfung und Feature-Branch-Push fehlen noch.
Es wurde kein echter API-Key angefordert, angezeigt oder konfiguriert und keine
Cloudanfrage ausgeführt.
+121
View File
@@ -0,0 +1,121 @@
[CmdletBinding()]
param(
[string]$UvPath,
[string]$OllamaPath,
[string]$OllamaModels,
[string]$DataDir,
[string]$UvCacheDir,
[string]$PythonInstallDir
)
$ErrorActionPreference = 'Stop'
function Get-ConfiguredPath {
param(
[string]$ParameterValue,
[string]$EnvironmentName,
[string]$DefaultValue
)
if (-not [string]::IsNullOrWhiteSpace($ParameterValue)) {
return [System.IO.Path]::GetFullPath($ParameterValue)
}
$environmentValue = [System.Environment]::GetEnvironmentVariable($EnvironmentName)
if (-not [string]::IsNullOrWhiteSpace($environmentValue)) {
return [System.IO.Path]::GetFullPath($environmentValue)
}
return [System.IO.Path]::GetFullPath($DefaultValue)
}
function Test-OllamaReady {
try {
$null = Invoke-RestMethod `
-Uri 'http://127.0.0.1:11434/api/version' `
-Method Get `
-TimeoutSec 2
return $true
}
catch {
return $false
}
}
$repositoryRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..'))
if (-not (Test-Path -LiteralPath (Join-Path $repositoryRoot 'pyproject.toml') -PathType Leaf)) {
throw "Das Repository konnte relativ zum Startskript nicht verifiziert werden."
}
$driveRoot = [System.IO.Path]::GetPathRoot($repositoryRoot)
$resolvedUv = Get-ConfiguredPath `
-ParameterValue $UvPath `
-EnvironmentName 'JAVIS_UV_PATH' `
-DefaultValue (Join-Path $driveRoot 'Javis-Tools\uv\uv.exe')
$resolvedOllama = Get-ConfiguredPath `
-ParameterValue $OllamaPath `
-EnvironmentName 'JAVIS_OLLAMA_PATH' `
-DefaultValue (Join-Path $driveRoot 'Javis-Tools\ollama\ollama.exe')
$resolvedModels = Get-ConfiguredPath `
-ParameterValue $OllamaModels `
-EnvironmentName 'JAVIS_OLLAMA_MODELS' `
-DefaultValue (Join-Path $driveRoot 'Javis-Data\ollama-models')
$resolvedData = Get-ConfiguredPath `
-ParameterValue $DataDir `
-EnvironmentName 'JAVIS_DATA_DIR' `
-DefaultValue (Join-Path $driveRoot 'Javis-Data\runtime')
$resolvedCache = Get-ConfiguredPath `
-ParameterValue $UvCacheDir `
-EnvironmentName 'JAVIS_UV_CACHE_DIR' `
-DefaultValue (Join-Path $driveRoot 'Javis-Tools\uv-cache')
$resolvedPython = Get-ConfiguredPath `
-ParameterValue $PythonInstallDir `
-EnvironmentName 'JAVIS_PYTHON_INSTALL_DIR' `
-DefaultValue (Join-Path $driveRoot 'Javis-Tools\python')
if (-not (Test-Path -LiteralPath $resolvedUv -PathType Leaf)) {
throw "uv.exe wurde nicht gefunden: $resolvedUv"
}
if (-not (Test-Path -LiteralPath $resolvedModels -PathType Container)) {
throw "Der externe Ollama-Modellpfad wurde nicht gefunden: $resolvedModels"
}
$env:JAVIS_DATA_DIR = $resolvedData
$env:OLLAMA_MODELS = $resolvedModels
$env:OLLAMA_HOST = '127.0.0.1:11434'
$env:UV_CACHE_DIR = $resolvedCache
$env:UV_PYTHON_INSTALL_DIR = $resolvedPython
if (-not (Test-OllamaReady)) {
if (-not (Test-Path -LiteralPath $resolvedOllama -PathType Leaf)) {
throw "Ollama ist nicht erreichbar und ollama.exe wurde nicht gefunden: $resolvedOllama"
}
Write-Host "Ollama wird lokal auf 127.0.0.1:11434 gestartet ..."
$ollamaProcess = Start-Process `
-FilePath $resolvedOllama `
-ArgumentList 'serve' `
-WindowStyle Hidden `
-PassThru
$ready = $false
for ($attempt = 1; $attempt -le 30; $attempt++) {
if ($ollamaProcess.HasExited) {
throw "Ollama wurde beendet, bevor die lokale API bereit war."
}
Start-Sleep -Milliseconds 500
if (Test-OllamaReady) {
$ready = $true
break
}
}
if (-not $ready) {
throw "Ollama war nach 15 Sekunden nicht unter 127.0.0.1:11434 erreichbar."
}
}
Push-Location $repositoryRoot
try {
& $resolvedUv run javis chat
exit $LASTEXITCODE
}
finally {
Pop-Location
}
+30
View File
@@ -0,0 +1,30 @@
import unittest
from pathlib import Path
class StartScriptTests(unittest.TestCase):
def test_script_is_local_overridable_and_avoids_system_changes(self) -> None:
repository_root = Path(__file__).resolve().parents[2]
script = (repository_root / "scripts" / "start-javis.ps1").read_text(encoding="utf-8")
normalized = script.lower()
self.assertIn("$psscriptroot", normalized)
self.assertIn("http://127.0.0.1:11434/api/version", normalized)
self.assertIn("-windowstyle hidden", normalized)
self.assertIn("javis_uv_path", normalized)
self.assertIn("javis_ollama_path", normalized)
self.assertIn("javis_data_dir", normalized)
self.assertIn("run javis chat", normalized)
self.assertNotIn("c:\\users\\", normalized)
for forbidden in (
"set-executionpolicy",
"setx ",
"new-service",
"schtasks",
"hkey_",
):
self.assertNotIn(forbidden, normalized)
if __name__ == "__main__":
unittest.main()