mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-24 07:28:13 +02:00
v0.2.19 : preset actif de nouveau détecté (empreinte ignore les clés appareil MEM_MODE/CRAWL4AI_URL) + surbrillance bleue du preset actif
This commit is contained in:
1 parent
20dd09abc6
commit
acb08d3c6a
6 files changed
+48
-13
No files matched your search
@@ -16,7 +16,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
const Version = "0.2.18"
|
const Version = "0.2.19"
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Migration one-shot des anciens skills (SKILLS/<nom>/SKILL.md) vers la
|
// Migration one-shot des anciens skills (SKILLS/<nom>/SKILL.md) vers la
|
||||||
|
|||||||
+40
-5
@@ -51,15 +51,51 @@ func withDisplayName(content, name string) string {
|
|||||||
return line + "\n" + content
|
return line + "\n" + content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// presetFingerprint hashes config content while IGNORING the device-level keys
|
||||||
|
// (preservedKeys) that SwitchToPreset re-applies on top of a freshly copied
|
||||||
|
// preset. Without this, those injected MEM_MODE/CRAWL4AI_URL lines make
|
||||||
|
// config.env differ from every preset file, so no preset is ever detected as
|
||||||
|
// active (regression introduced when preservedKeys were added). We strip those
|
||||||
|
// assignment lines symmetrically from both sides before hashing so a plain
|
||||||
|
// content match still identifies the active preset.
|
||||||
|
func presetFingerprint(content []byte) string {
|
||||||
|
var b strings.Builder
|
||||||
|
for _, line := range strings.Split(string(content), "\n") {
|
||||||
|
if isPreservedAssignment(line) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
b.WriteString(line)
|
||||||
|
b.WriteByte('\n')
|
||||||
|
}
|
||||||
|
h := sha1.Sum([]byte(b.String()))
|
||||||
|
return hex.EncodeToString(h[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
// isPreservedAssignment reports whether a line assigns one of the preservedKeys
|
||||||
|
// (commented or not), e.g. `MEM_MODE=off` or `# CRAWL4AI_URL=...`.
|
||||||
|
func isPreservedAssignment(line string) bool {
|
||||||
|
t := strings.TrimSpace(strings.TrimPrefix(strings.TrimSpace(line), "#"))
|
||||||
|
eq := strings.IndexByte(t, '=')
|
||||||
|
if eq < 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
key := strings.TrimSpace(t[:eq])
|
||||||
|
for _, k := range preservedKeys {
|
||||||
|
if key == k {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// ListPresets returns all configs/*.env, marking the one whose contents match
|
// ListPresets returns all configs/*.env, marking the one whose contents match
|
||||||
// the current config.env (by SHA-1), sorted by display name.
|
// the current config.env (ignoring device-level preservedKeys), sorted by name.
|
||||||
func ListPresets() ([]Preset, error) {
|
func ListPresets() ([]Preset, error) {
|
||||||
dir := presetsDir()
|
dir := presetsDir()
|
||||||
_ = os.MkdirAll(dir, 0o755)
|
_ = os.MkdirAll(dir, 0o755)
|
||||||
cur := ""
|
cur := ""
|
||||||
if b, err := os.ReadFile(confPath()); err == nil {
|
if b, err := os.ReadFile(confPath()); err == nil {
|
||||||
h := sha1.Sum(b)
|
cur = presetFingerprint(b)
|
||||||
cur = hex.EncodeToString(h[:])
|
|
||||||
}
|
}
|
||||||
entries, err := os.ReadDir(dir)
|
entries, err := os.ReadDir(dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -75,13 +111,12 @@ func ListPresets() ([]Preset, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
h := sha1.Sum(b)
|
|
||||||
id := strings.TrimSuffix(e.Name(), ".env")
|
id := strings.TrimSuffix(e.Name(), ".env")
|
||||||
out = append(out, Preset{
|
out = append(out, Preset{
|
||||||
ID: id,
|
ID: id,
|
||||||
Name: presetDisplayName(string(b), id),
|
Name: presetDisplayName(string(b), id),
|
||||||
Path: p,
|
Path: p,
|
||||||
Active: hex.EncodeToString(h[:]) == cur,
|
Active: presetFingerprint(b) == cur,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
|
sort.Slice(out, func(i, j int) bool { return out[i].Name < out[j].Name })
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+4
-4
@@ -21,9 +21,9 @@
|
|||||||
thème plus tard : 1) copier un bloc [data-theme="…"] ci-dessous en changeant
|
thème plus tard : 1) copier un bloc [data-theme="…"] ci-dessous en changeant
|
||||||
les valeurs, 2) ajouter son {id,label} au registre THEMES (voir le JS). Le
|
les valeurs, 2) ajouter son {id,label} au registre THEMES (voir le JS). Le
|
||||||
reste (sélecteur, persistance, application) est automatique. */
|
reste (sélecteur, persistance, application) est automatique. */
|
||||||
:root{color-scheme:dark;--bg:#0d1117;--panel:#161b22;--border:#30363d;--text:#e6edf3;--dim:#7d8590;--accent:#58a6ff;--ok:#58a6ff;--warn:#d29922;--err:#f85149;--mag:#bc8cff;--code-bg:#0d1117;--danger-bg:#3d1f23;--warn-bg:#3d2f1f}
|
:root{color-scheme:dark;--bg:#0d1117;--panel:#161b22;--border:#30363d;--text:#e6edf3;--dim:#7d8590;--accent:#58a6ff;--accent-bg:rgba(88,166,255,.12);--ok:#58a6ff;--warn:#d29922;--err:#f85149;--mag:#bc8cff;--code-bg:#0d1117;--danger-bg:#3d1f23;--warn-bg:#3d2f1f}
|
||||||
[data-theme="dark"]{color-scheme:dark;--bg:#0d1117;--panel:#161b22;--border:#30363d;--text:#e6edf3;--dim:#7d8590;--accent:#58a6ff;--ok:#58a6ff;--warn:#d29922;--err:#f85149;--mag:#bc8cff;--code-bg:#0d1117;--danger-bg:#3d1f23;--warn-bg:#3d2f1f}
|
[data-theme="dark"]{color-scheme:dark;--bg:#0d1117;--panel:#161b22;--border:#30363d;--text:#e6edf3;--dim:#7d8590;--accent:#58a6ff;--accent-bg:rgba(88,166,255,.12);--ok:#58a6ff;--warn:#d29922;--err:#f85149;--mag:#bc8cff;--code-bg:#0d1117;--danger-bg:#3d1f23;--warn-bg:#3d2f1f}
|
||||||
[data-theme="light"]{color-scheme:light;--bg:#f0f1f4;--panel:#f8f9fb;--border:#d7dbe1;--text:#24292f;--dim:#636b74;--accent:#0969da;--ok:#0969da;--warn:#9a6700;--err:#cf222e;--mag:#8250df;--code-bg:#e6e9ee;--danger-bg:#fbe6e6;--warn-bg:#fbefda}
|
[data-theme="light"]{color-scheme:light;--bg:#f0f1f4;--panel:#f8f9fb;--border:#d7dbe1;--text:#24292f;--dim:#636b74;--accent:#0969da;--accent-bg:rgba(9,105,218,.10);--ok:#0969da;--warn:#9a6700;--err:#cf222e;--mag:#8250df;--code-bg:#e6e9ee;--danger-bg:#fbe6e6;--warn-bg:#fbefda}
|
||||||
*{box-sizing:border-box}
|
*{box-sizing:border-box}
|
||||||
body{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--bg);color:var(--text);height:100vh;height:100dvh;display:flex;font-size:14px}
|
body{margin:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;background:var(--bg);color:var(--text);height:100vh;height:100dvh;display:flex;font-size:14px}
|
||||||
/* PWA plein écran (viewport-fit=cover) : on décale le contenu des bords pour ne
|
/* PWA plein écran (viewport-fit=cover) : on décale le contenu des bords pour ne
|
||||||
@@ -134,7 +134,7 @@ button:disabled{opacity:.5;cursor:not-allowed}
|
|||||||
.row{display:flex;gap:4px;flex-wrap:wrap}
|
.row{display:flex;gap:4px;flex-wrap:wrap}
|
||||||
.preset{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:6px 10px;border:1px solid var(--border);border-radius:6px;margin:4px 0;cursor:pointer;background:var(--panel)}
|
.preset{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:6px 10px;border:1px solid var(--border);border-radius:6px;margin:4px 0;cursor:pointer;background:var(--panel)}
|
||||||
.preset:hover{border-color:var(--accent)}
|
.preset:hover{border-color:var(--accent)}
|
||||||
.preset.active{border-color:var(--ok);color:var(--ok)}
|
.preset.active{border-color:var(--accent);color:var(--accent);border-width:1.5px;padding:5.5px 9.5px}
|
||||||
.preset>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
.preset>span{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
||||||
.preset>button{flex-shrink:0}
|
.preset>button{flex-shrink:0}
|
||||||
.preset-info{flex:1;min-width:0}
|
.preset-info{flex:1;min-width:0}
|
||||||
|
|||||||
+3
-3
@@ -3,13 +3,13 @@
|
|||||||
"FileVersion": {
|
"FileVersion": {
|
||||||
"Major": 0,
|
"Major": 0,
|
||||||
"Minor": 2,
|
"Minor": 2,
|
||||||
"Patch": 18,
|
"Patch": 19,
|
||||||
"Build": 0
|
"Build": 0
|
||||||
},
|
},
|
||||||
"ProductVersion": {
|
"ProductVersion": {
|
||||||
"Major": 0,
|
"Major": 0,
|
||||||
"Minor": 2,
|
"Minor": 2,
|
||||||
"Patch": 18,
|
"Patch": 19,
|
||||||
"Build": 0
|
"Build": 0
|
||||||
},
|
},
|
||||||
"FileFlagsMask": "3f",
|
"FileFlagsMask": "3f",
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
"LegalCopyright": "Copyright (c) 2026 Jean contributors. MIT License.",
|
"LegalCopyright": "Copyright (c) 2026 Jean contributors. MIT License.",
|
||||||
"OriginalFilename": "jean.exe",
|
"OriginalFilename": "jean.exe",
|
||||||
"ProductName": "Jean",
|
"ProductName": "Jean",
|
||||||
"ProductVersion": "0.2.18",
|
"ProductVersion": "0.2.19",
|
||||||
"Comments": "https://github.com/nathaninline/jean — projet open source (MIT)"
|
"Comments": "https://github.com/nathaninline/jean — projet open source (MIT)"
|
||||||
},
|
},
|
||||||
"VarFileInfo": {
|
"VarFileInfo": {
|
||||||
|
|||||||
Reference in new issue
Block a user