diff --git a/internal/jean/backend_serve.go b/internal/jean/backend_serve.go index d6d40e2..149ecff 100644 --- a/internal/jean/backend_serve.go +++ b/internal/jean/backend_serve.go @@ -19,6 +19,20 @@ func cmdServe(args []string) error { if model == "" { return fmt.Errorf("MODEL non défini dans %s", confPath()) } + // MODEL est enregistré sous forme de simple nom de fichier (les .gguf vivent + // dans JEAN_HOME) : sous systemd/launchd le WorkingDirectory vaut JEAN_HOME, + // donc le chemin relatif tombait juste. Lancé depuis une app de bureau, le + // répertoire courant est « / » et llama-server ne trouvait rien. On résout + // donc explicitement, quel que soit le contexte de lancement. + if !filepath.IsAbs(model) { + model = filepath.Join(JeanHome(), model) + } + if _, err := os.Stat(model); err != nil { + return fmt.Errorf("modèle introuvable : %s", model) + } + if !filepath.IsAbs(bin) { + bin = filepath.Join(JeanHome(), bin) + } // Make sure llama-server can find its bundled shared libraries (the .so/.dll // neighbours of the binary). This is platform-specific: LD_LIBRARY_PATH on diff --git a/internal/jean/sys_console_darwin.go b/internal/jean/sys_console_darwin.go index f3d0096..2dcc927 100644 --- a/internal/jean/sys_console_darwin.go +++ b/internal/jean/sys_console_darwin.go @@ -36,6 +36,28 @@ func setupConsole() bool { return true } +// appWarning signale une situation de lancement qui casse Jean de façon peu +// évidente. Aujourd'hui : l'App Translocation de Gatekeeper. Une app non signée +// ouverte depuis Téléchargements est exécutée depuis une copie en LECTURE SEULE +// sous /private/var/folders/…/AppTranslocation//, à un chemin différent à +// CHAQUE lancement. Conséquences vécues : plusieurs instances qui se marchent +// dessus (la seconde trouve le port 8090 occupé et se contente d'ouvrir l'UI de +// la première, souvent une version périmée), des process fantômes issus de +// copies précédentes, et une mise à jour en place impossible. +// Le remède est côté utilisateur : déplacer Jean.app dans /Applications. +func appWarning() string { + exe, err := os.Executable() + if err != nil { + return "" + } + if !strings.Contains(exe, "/AppTranslocation/") { + return "" + } + return "Jean tourne depuis une copie temporaire en lecture seule (App Translocation de macOS). " + + "Fermez l'app, déplacez Jean.app dans le dossier Applications, puis rouvrez-la — " + + "sinon chaque lancement crée une instance séparée et les mises à jour du moteur échouent." +} + // fixFinderPath complète le PATH famélique hérité du Finder. Une app lancée par // LaunchServices reçoit /usr/bin:/bin:/usr/sbin:/sbin — pas les dossiers de // Homebrew : sans ça, Jean ne voit ni `brew`, ni `cmake`, ni `git`, et la diff --git a/internal/jean/sys_console_other.go b/internal/jean/sys_console_other.go index d8539b2..1dee73a 100644 --- a/internal/jean/sys_console_other.go +++ b/internal/jean/sys_console_other.go @@ -8,3 +8,7 @@ package jean // sys_console_windows.go (double-clic sur jean.exe) et sys_console_darwin.go // (ouverture de Jean.app depuis le Finder). func setupConsole() bool { return true } + +// appWarning : rien à signaler hors macOS (l'App Translocation est spécifique à +// Gatekeeper). Voir sys_console_darwin.go. +func appWarning() string { return "" } diff --git a/internal/jean/sys_console_windows.go b/internal/jean/sys_console_windows.go index c730f07..d8e8b56 100644 --- a/internal/jean/sys_console_windows.go +++ b/internal/jean/sys_console_windows.go @@ -58,3 +58,7 @@ func configureConsole() { _, _, _ = k.NewProc("SetConsoleMode").Call(h, uintptr(mode|enableVirtualTerminalProcessing)) } } + +// appWarning : rien à signaler sous Windows (pas d'App Translocation). Voir +// sys_console_darwin.go. +func appWarning() string { return "" } diff --git a/internal/jean/sys_service_darwin.go b/internal/jean/sys_service_darwin.go index dc26195..ca9e609 100644 --- a/internal/jean/sys_service_darwin.go +++ b/internal/jean/sys_service_darwin.go @@ -184,6 +184,10 @@ func userSvcStart() error { cmd := exec.Command(self, "serve") cmd.Stdout, cmd.Stderr = logf, logf + // Même répertoire de travail que sous systemd/launchd : les chemins relatifs + // de config.env (MODEL=…gguf) se résolvent depuis JEAN_HOME, pas depuis « / » + // que nous hérite le Finder. + cmd.Dir = JeanHome() cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true} if err := cmd.Start(); err != nil { return fmt.Errorf("démarrage de 'jean serve': %w", err) diff --git a/internal/jean/sys_service_windows.go b/internal/jean/sys_service_windows.go index be98fe8..ccf50a2 100644 --- a/internal/jean/sys_service_windows.go +++ b/internal/jean/sys_service_windows.go @@ -71,6 +71,7 @@ func svcStart() error { cmd := exec.Command(self, "serve") cmd.Stdout = logf cmd.Stderr = logf + cmd.Dir = JeanHome() // les chemins relatifs de config.env se résolvent depuis JEAN_HOME // createNoWindow + HideWindow : le service enfant (`jean serve`) ne doit JAMAIS // faire clignoter de console noire quand Jean est lancé en mode app (double-clic). cmd.SysProcAttr = &syscall.SysProcAttr{ diff --git a/internal/jean/ui/index.html b/internal/jean/ui/index.html index e9cebc1..4b9ee3a 100644 --- a/internal/jean/ui/index.html +++ b/internal/jean/ui/index.html @@ -401,6 +401,8 @@ button:disabled{opacity:.5;cursor:not-allowed}

ajean

… + + + +