mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Remonte par un utilisateur Windows non administrateur. Renommer C:\ProgramData\jean exige d'ecrire dans C:\ProgramData, ce qu'un compte standard ne peut pas faire : le rename echouait a chaque lancement et le message technique s'affichait avant CHAQUE commande, y compris `ajean help`. Rien n'etait casse — le repli sur l'ancien chemin fonctionne comme prevu et aucune donnee n'est en jeu. Le defaut etait entierement dans l'affichage : un detail interne presente comme une erreur, sur une situation permanente et sans consequence. La raison est desormais enregistree au lieu d'etre imprimee, et ressortie la ou elle est actionnable : `ajean where`, qui parle justement d'emplacements, avec la marche a suivre. `ajean install` en administrateur retente la migration — c'est le seul moment ou les droits sont reunis — et le fait AVANT de resoudre le dossier, sinon la variable resterait sur l'ancien chemin et on installerait a cote. La cause du rename est extraite du *os.LinkError : son texte repete les deux chemins complets, ce qui donnait trois fois les memes chemins dans un message qui les cite deja et noyait l'essentiel (« Acces refuse »). Deux tests : l'echec reste silencieux mais enregistre, et aucun message parasite quand la migration reussit. Verifie sur un cas reproduit — `help` est propre, `where` affiche le conseil.
91 lines
3.2 KiB
Go
91 lines
3.2 KiB
Go
package ajean
|
|
|
|
import (
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"runtime"
|
|
)
|
|
|
|
// « Où sont mes fichiers ? » — la question que personne ne devrait avoir à poser.
|
|
// Un binaire unique qui s'auto-installe au premier lancement rend les
|
|
// emplacements invisibles : on ne sait plus si le .exe qu'on a double-cliqué EST
|
|
// l'application ou seulement un installateur, ni où atterrissent la config, les
|
|
// modèles et les fichiers que l'agent écrit. On centralise donc la réponse ici,
|
|
// et on l'expose à la fois en ligne de commande (`ajean where`) et dans l'UI.
|
|
|
|
type ajeanPaths struct {
|
|
Home string `json:"home"` // AJEAN_HOME : racine des données
|
|
Config string `json:"config"` // config.env
|
|
Exe string `json:"exe"` // binaire en cours d'exécution
|
|
Installed string `json:"installed"` // binaire installé (peut différer de Exe)
|
|
Workspace string `json:"workspace"` // dossier de travail du mode agent
|
|
Memory string `json:"memory"`
|
|
Presets string `json:"presets"`
|
|
}
|
|
|
|
// installedExePath est l'emplacement canonique du binaire après installation.
|
|
// Il diffère par plateforme : sous Unix les installateurs posent /usr/local/bin/ajean
|
|
// (c'est ce que référencent les unités systemd et le plist launchd) ; sous Windows,
|
|
// faute d'équivalent, on utilise AJEAN_HOME\bin ajouté au PATH utilisateur.
|
|
func installedExePath() string { return exePathNamed("ajean") }
|
|
|
|
// legacyExePath est l'emplacement d'avant le renommage. L'installation continue
|
|
// d'y poser un alias : `jean` reste tapable indéfiniment. Ça ne coûte qu'un lien
|
|
// et ça préserve les habitudes, les scripts cron, les alias shell et les tutos
|
|
// déjà écrits par les utilisateurs — dont on ne contrôle aucun.
|
|
func legacyExePath() string { return exePathNamed("jean") }
|
|
|
|
func exePathNamed(name string) string {
|
|
if runtime.GOOS == "windows" {
|
|
return filepath.Join(AjeanHome(), "bin", name+".exe")
|
|
}
|
|
return "/usr/local/bin/" + name
|
|
}
|
|
|
|
func currentPaths() ajeanPaths {
|
|
exe, _ := os.Executable()
|
|
if resolved, err := filepath.EvalSymlinks(exe); err == nil {
|
|
exe = resolved
|
|
}
|
|
return ajeanPaths{
|
|
Home: AjeanHome(),
|
|
Config: confPath(),
|
|
Exe: exe,
|
|
Installed: installedExePath(),
|
|
Workspace: agentWorkspace(),
|
|
Memory: memoryDir(),
|
|
Presets: presetsDir(),
|
|
}
|
|
}
|
|
|
|
func cmdWhere(args []string) error {
|
|
p := currentPaths()
|
|
fmt.Printf("Emplacements AJEAN\n\n")
|
|
for _, row := range [][2]string{
|
|
{"données (AJEAN_HOME)", p.Home},
|
|
{"configuration", p.Config},
|
|
{"binaire en cours", p.Exe},
|
|
{"binaire installé", p.Installed},
|
|
{"travail de l'agent", p.Workspace},
|
|
{"mémoire", p.Memory},
|
|
{"presets", p.Presets},
|
|
} {
|
|
fmt.Printf(" %-20s %s\n", row[0], row[1])
|
|
}
|
|
if notice := homeMigrationNotice(); notice != "" {
|
|
fmt.Printf("\n%s %s\n", yellow("[info]"), notice)
|
|
}
|
|
if p.Exe != p.Installed {
|
|
fmt.Printf("\n%s tu exécutes une copie qui n'est PAS le binaire installé.\n", dim("[info]"))
|
|
fmt.Printf(" Les mises à jour depuis l'application ne modifient que la copie lancée.\n")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// handlePaths (GET /api/paths) alimente le bloc « Emplacements » de l'UI.
|
|
func handlePaths(w http.ResponseWriter, r *http.Request) {
|
|
sendJSON(w, 200, currentPaths())
|
|
}
|