Settings › About: the Desktop release the server recommends (GET /apps)
ci / ui (push) Waiting to run
ci / check (push) Failing after 3s
ci / start (push) Failing after 3s

Offered when newer than this install, a beta only to a beta install, and
only with the project's own release page as the link.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-11-10 14:19:11 +00:00
1 parent 9b07527c3a
commit 3101552858
8 files changed
+185 -2

No files matched your search

+3
View File
@@ -49,6 +49,9 @@ All notable changes to LLeMbas Desktop. The format follows
with Open and Run again (and Pause, when a task has failed three times in a row), labelled in
the account's language. Open, or a click on the notification, opens the task; Run again and
Pause do it without opening the window. A chat's notification, clicked, opens that chat.
- **The release your server recommends.** Settings › About names the Desktop release that goes
with the server's version when it is newer than this one (a beta only to a beta install), with
a link to its release page.
### Fixed
+1 -1
View File
@@ -16,7 +16,7 @@ OUT="tests/ui/fixtures"
FILES="chat_agent.json event_ask.json event_status.json event_status_idle.json event_status_person.json
event_status_stopped.json event_tree.json models_agent.json subagent_findings.json subagent_transcript.json tree.json
me.json folders.json folder.json search.json memories.json memory.json scope.json push_schedule.json push_schedule_failed.json
event_schedules.json schedule.json schedule_run.json chat.json chats_listed.json files_listing.json"
apps.json apps_stable.json event_schedules.json schedule.json schedule_run.json chat.json chats_listed.json files_listing.json"
[ $# -eq 1 ] || { echo "usage: scripts/fetch-fixtures.sh <server-ref>" >&2; exit 2; }
commit="$(git -C "$SERVER" rev-parse --verify --quiet "$1^{commit}")" \
+28
View File
@@ -520,6 +520,10 @@ KEYS = (
"Draw",
"Drawing… a picture can take a minute or two.",
"The server's answer had no picture in it.",
# settings.js: the release the server recommends
"Your server recommends LLeMbas Desktop %(version)s",
"The release that goes with the server's version. This is %(current)s.",
"Open the release page",
)
# The app's own sentences. The mode names (Manual, Edit, Auto, Plan) stay English, as the
@@ -790,6 +794,9 @@ OWN: dict[str, dict[str, str]] = {
"Draw": "Nakreslit",
"Drawing… a picture can take a minute or two.": "Kreslím… obrázek může trvat minutu nebo dvě.",
"The server's answer had no picture in it.": "V odpovědi serveru nebyl žádný obrázek.",
"Your server recommends LLeMbas Desktop %(version)s": "Váš server doporučuje LLeMbas Desktop %(version)s",
"The release that goes with the server's version. This is %(current)s.": "Vydání, které patří k verzi serveru. Toto je %(current)s.",
"Open the release page": "Otevřít stránku vydání",
},
"de": {
"Sign in again: the server no longer accepts this app's sign-in.": "Melden Sie sich erneut an: Der Server nimmt die Anmeldung dieser App nicht mehr an.",
@@ -1055,6 +1062,9 @@ OWN: dict[str, dict[str, str]] = {
"Draw": "Zeichnen",
"Drawing… a picture can take a minute or two.": "Wird gezeichnet… ein Bild kann ein bis zwei Minuten dauern.",
"The server's answer had no picture in it.": "Die Antwort des Servers enthielt kein Bild.",
"Your server recommends LLeMbas Desktop %(version)s": "Ihr Server empfiehlt LLeMbas Desktop %(version)s",
"The release that goes with the server's version. This is %(current)s.": "Die Version, die zur Version des Servers passt. Dies ist %(current)s.",
"Open the release page": "Release-Seite öffnen",
},
"es": {
"Sign in again: the server no longer accepts this app's sign-in.": "Vuelva a iniciar sesión: el servidor ya no acepta el inicio de sesión de esta aplicación.",
@@ -1320,6 +1330,9 @@ OWN: dict[str, dict[str, str]] = {
"Draw": "Dibujar",
"Drawing… a picture can take a minute or two.": "Dibujando… una imagen puede tardar uno o dos minutos.",
"The server's answer had no picture in it.": "La respuesta del servidor no traía ninguna imagen.",
"Your server recommends LLeMbas Desktop %(version)s": "Su servidor recomienda LLeMbas Desktop %(version)s",
"The release that goes with the server's version. This is %(current)s.": "La versión que corresponde a la del servidor. Esta es %(current)s.",
"Open the release page": "Abrir la página de la versión",
},
"fr": {
"Sign in again: the server no longer accepts this app's sign-in.": "Reconnectez-vous : le serveur n’accepte plus la connexion de cette application.",
@@ -1585,6 +1598,9 @@ OWN: dict[str, dict[str, str]] = {
"Draw": "Dessiner",
"Drawing… a picture can take a minute or two.": "Dessin en cours… une image peut prendre une minute ou deux.",
"The server's answer had no picture in it.": "La réponse du serveur ne contenait aucune image.",
"Your server recommends LLeMbas Desktop %(version)s": "Votre serveur recommande LLeMbas Desktop %(version)s",
"The release that goes with the server's version. This is %(current)s.": "La version qui va avec celle du serveur. Celle-ci est la %(current)s.",
"Open the release page": "Ouvrir la page de la version",
},
"hu": {
"Sign in again: the server no longer accepts this app's sign-in.": "Jelentkezzen be újra: a szerver már nem fogadja el ennek az alkalmazásnak a bejelentkezését.",
@@ -1850,6 +1866,9 @@ OWN: dict[str, dict[str, str]] = {
"Draw": "Rajzolás",
"Drawing… a picture can take a minute or two.": "Rajzolás… egy kép egy-két percig is eltarthat.",
"The server's answer had no picture in it.": "A szerver válaszában nem volt kép.",
"Your server recommends LLeMbas Desktop %(version)s": "A szervere a LLeMbas Desktop %(version)s verziót ajánlja",
"The release that goes with the server's version. This is %(current)s.": "A szerver verziójához tartozó kiadás. Ez a %(current)s.",
"Open the release page": "Kiadás oldalának megnyitása",
},
"it": {
"Sign in again: the server no longer accepts this app's sign-in.": "Accedi di nuovo: il server non accetta più l’accesso di questa app.",
@@ -2115,6 +2134,9 @@ OWN: dict[str, dict[str, str]] = {
"Draw": "Disegna",
"Drawing… a picture can take a minute or two.": "Disegno in corso… un’immagine può richiedere un minuto o due.",
"The server's answer had no picture in it.": "La risposta del server non conteneva immagini.",
"Your server recommends LLeMbas Desktop %(version)s": "Il tuo server consiglia LLeMbas Desktop %(version)s",
"The release that goes with the server's version. This is %(current)s.": "La versione che va con quella del server. Questa è la %(current)s.",
"Open the release page": "Apri la pagina della versione",
},
"pl": {
"Sign in again: the server no longer accepts this app's sign-in.": "Zaloguj się ponownie: serwer nie przyjmuje już logowania tej aplikacji.",
@@ -2380,6 +2402,9 @@ OWN: dict[str, dict[str, str]] = {
"Draw": "Narysuj",
"Drawing… a picture can take a minute or two.": "Rysowanie… obraz może zająć minutę lub dwie.",
"The server's answer had no picture in it.": "W odpowiedzi serwera nie było obrazu.",
"Your server recommends LLeMbas Desktop %(version)s": "Twój serwer zaleca LLeMbas Desktop %(version)s",
"The release that goes with the server's version. This is %(current)s.": "Wydanie pasujące do wersji serwera. To jest %(current)s.",
"Open the release page": "Otwórz stronę wydania",
},
"sk": {
"Sign in again: the server no longer accepts this app's sign-in.": "Prihláste sa znova: server už neprijíma prihlásenie tejto aplikácie.",
@@ -2645,6 +2670,9 @@ OWN: dict[str, dict[str, str]] = {
"Draw": "Nakresliť",
"Drawing… a picture can take a minute or two.": "Kreslím… obrázok môže trvať minútu alebo dve.",
"The server's answer had no picture in it.": "V odpovedi servera nebol žiadny obrázok.",
"Your server recommends LLeMbas Desktop %(version)s": "Váš server odporúča LLeMbas Desktop %(version)s",
"The release that goes with the server's version. This is %(current)s.": "Vydanie, ktoré patrí k verzii servera. Toto je %(current)s.",
"Open the release page": "Otvoriť stránku vydania",
},
}
+20
View File
@@ -0,0 +1,20 @@
{
"server": {
"version": "2.1.0-beta.3",
"channel": "beta"
},
"apps": {
"android": {
"version": "1.1.0-beta.2",
"tag": "v1.1.0-beta.2",
"channel": "beta",
"page": "https://github.com/LLeMbas/LLeMbas-Android/releases/tag/v1.1.0-beta.2"
},
"desktop": {
"version": "1.0.1",
"tag": "v1.0.1",
"channel": "stable",
"page": "https://github.com/LLeMbas/LLeMbas-Desktop/releases/tag/v1.0.1"
}
}
}
+15
View File
@@ -0,0 +1,15 @@
{
"server": {
"version": "2.0.0",
"channel": "stable"
},
"apps": {
"android": null,
"desktop": {
"version": "1.0.1",
"tag": "v1.0.1",
"channel": "stable",
"page": "https://github.com/LLeMbas/LLeMbas-Desktop/releases/tag/v1.0.1"
}
}
}
+36
View File
@@ -1550,6 +1550,42 @@ test("J8: a scheduled run's notification opens its task, and a chat's opens the
assert.deepEqual(p.errors, [])
})
// K8: the release the server recommends (GET /apps), in Settings › About.
async function aboutWith(version, apps) {
const p = await page({ status: status({ version }), routes: baseRoutes({ "GET /apps": apps }), streams: {} })
await p.click("#settings-btn")
await p.waitForFunction(() => window.__mock.api("GET", "/apps").length === 1)
await p.waitForTimeout(100)
return p
}
test("K8: a newer release the server recommends is offered in About, with its release page", async () => {
const p = await aboutWith("1.0.0", fixture("apps_stable"))
await p.waitForSelector("#set-about >> text=Your server recommends LLeMbas Desktop 1.0.1")
await p.click("#set-about .btn >> text=Open the release page")
const opened = await p.evaluate(() => window.__mock.calls.filter((c) => c.cmd === "open_external").map((c) => c.args.url))
assert.deepEqual(opened, ["https://github.com/LLeMbas/LLeMbas-Desktop/releases/tag/v1.0.1"])
await shot(p, "k8-about-1280")
assert.deepEqual(p.errors, [])
})
test("K8: nothing is offered that is not newer, a beta to a stable install, or a page elsewhere", async () => {
const beta = { apps: { desktop: { version: "1.1.0-beta.2", tag: "v1.1.0-beta.2", channel: "beta", page: "https://github.com/LLeMbas/LLeMbas-Desktop/releases/tag/v1.1.0-beta.2" } } }
for (const [mine, apps, shown] of [
["1.0.1", fixture("apps_stable"), false],
["1.0.0", beta, false],
["1.0.0-beta.6", beta, true],
["1.0.0", { apps: { desktop: { version: "1.0.2", page: "https://elsewhere.example/releases/tag/v1.0.2" } } }, false],
["1.0.0", { __error: { status: 404, detail: "Not Found" } }, false],
]) {
const p = await aboutWith(mine, apps)
assert.equal(await p.locator("#set-about >> text=Your server recommends").count(), shown ? 1 : 0, `${mine} ← ${JSON.stringify(apps).slice(0, 60)}`)
assert.deepEqual(p.errors, [])
await p.context().close()
}
})
// --- Run ----------------------------------------------------------------------------------------
const only = process.argv[2] || ""
+24
View File
@@ -236,6 +236,7 @@ const LEMBAS_I18N = {
"Open the activity panel": "Otevřít panel aktivity",
"Open the chat": "Otevřít konverzaci",
"Open the page again": "Otevřít stránku znovu",
"Open the release page": "Otevřít stránku vydání",
"Or type an answer": "Nebo napište odpověď",
"Outputs": "Výstupy",
"Page": "Stránka",
@@ -364,6 +365,7 @@ const LEMBAS_I18N = {
"The numbers count this chat's own agent: 1 is the agent alone, with no subagents; Max 4 is the agent and up to 3 subagents. A subagent runs on the chat's model, or on another only when you name it in the chat.": "Čísla počítají i vlastního agenta konverzace: 1 je agent sám, bez podagentů; Max 4 je agent a až 3 podagenti. Podagent běží na modelu konverzace, na jiném jen tehdy, když ho v konverzaci pojmenujete.",
"The previous command": "Předchozí příkaz",
"The previous command (Ctrl+Shift+↑)": "Předchozí příkaz (Ctrl+Shift+↑)",
"The release that goes with the server's version. This is %(current)s.": "Vydání, které patří k verzi serveru. Toto je %(current)s.",
"The reply is ready.": "Odpověď je hotová.",
"The result is no longer there.": "Výsledek už tu není.",
"The server refused this computer's link: %(why)s": "Server odmítl propojení tohoto počítače: %(why)s",
@@ -424,6 +426,7 @@ const LEMBAS_I18N = {
"You asked: “%(text)s”": "Požádali jste: „%(text)s“",
"Your answer": "Vaše odpověď",
"Your files on the server, as the chats see them.": "Vaše soubory na serveru, tak jak je vidí konverzace.",
"Your server recommends LLeMbas Desktop %(version)s": "Váš server doporučuje LLeMbas Desktop %(version)s",
"a question": "otázka",
"agent connecting…": "agent se připojuje…",
"agent off": "agent vypnutý",
@@ -701,6 +704,7 @@ const LEMBAS_I18N = {
"Open the activity panel": "Aktivitätsbereich öffnen",
"Open the chat": "Chat öffnen",
"Open the page again": "Seite erneut öffnen",
"Open the release page": "Release-Seite öffnen",
"Or type an answer": "Oder eine Antwort eingeben",
"Outputs": "Ausgaben",
"Page": "Seite",
@@ -829,6 +833,7 @@ const LEMBAS_I18N = {
"The numbers count this chat's own agent: 1 is the agent alone, with no subagents; Max 4 is the agent and up to 3 subagents. A subagent runs on the chat's model, or on another only when you name it in the chat.": "Die Zahlen zählen den eigenen Agenten des Chats mit: 1 ist der Agent allein, ohne Subagenten; Max 4 ist der Agent und bis zu 3 Subagenten. Ein Subagent läuft auf dem Modell des Chats, auf einem anderen nur, wenn Sie es im Chat nennen.",
"The previous command": "Vorheriger Befehl",
"The previous command (Ctrl+Shift+↑)": "Vorheriger Befehl (Ctrl+Shift+↑)",
"The release that goes with the server's version. This is %(current)s.": "Die Version, die zur Version des Servers passt. Dies ist %(current)s.",
"The reply is ready.": "Die Antwort ist fertig.",
"The result is no longer there.": "Das Ergebnis ist nicht mehr da.",
"The server refused this computer's link: %(why)s": "Der Server hat die Verknüpfung dieses Computers abgelehnt: %(why)s",
@@ -889,6 +894,7 @@ const LEMBAS_I18N = {
"You asked: “%(text)s”": "Ihre Worte: „%(text)s“",
"Your answer": "Ihre Antwort",
"Your files on the server, as the chats see them.": "Ihre Dateien auf dem Server, so wie die Chats sie sehen.",
"Your server recommends LLeMbas Desktop %(version)s": "Ihr Server empfiehlt LLeMbas Desktop %(version)s",
"a question": "eine Frage",
"agent connecting…": "Agent verbindet…",
"agent off": "Agent aus",
@@ -1166,6 +1172,7 @@ const LEMBAS_I18N = {
"Open the activity panel": "Abrir el panel de actividad",
"Open the chat": "Abrir el chat",
"Open the page again": "Abrir la página de nuevo",
"Open the release page": "Abrir la página de la versión",
"Or type an answer": "O escriba una respuesta",
"Outputs": "Resultados",
"Page": "Página",
@@ -1294,6 +1301,7 @@ const LEMBAS_I18N = {
"The numbers count this chat's own agent: 1 is the agent alone, with no subagents; Max 4 is the agent and up to 3 subagents. A subagent runs on the chat's model, or on another only when you name it in the chat.": "Los números cuentan el agente propio del chat: 1 es el agente solo, sin subagentes; Máx. 4 es el agente y hasta 3 subagentes. Un subagente usa el modelo del chat, u otro solo si lo nombra en el chat.",
"The previous command": "El comando anterior",
"The previous command (Ctrl+Shift+↑)": "El comando anterior (Ctrl+Shift+↑)",
"The release that goes with the server's version. This is %(current)s.": "La versión que corresponde a la del servidor. Esta es %(current)s.",
"The reply is ready.": "La respuesta está lista.",
"The result is no longer there.": "El resultado ya no está.",
"The server refused this computer's link: %(why)s": "El servidor rechazó la vinculación de este equipo: %(why)s",
@@ -1354,6 +1362,7 @@ const LEMBAS_I18N = {
"You asked: “%(text)s”": "Usted pidió: «%(text)s»",
"Your answer": "Su respuesta",
"Your files on the server, as the chats see them.": "Sus archivos en el servidor, tal como los ven los chats.",
"Your server recommends LLeMbas Desktop %(version)s": "Su servidor recomienda LLeMbas Desktop %(version)s",
"a question": "una pregunta",
"agent connecting…": "agente conectando…",
"agent off": "agente apagado",
@@ -1631,6 +1640,7 @@ const LEMBAS_I18N = {
"Open the activity panel": "Ouvrir le panneau d’activité",
"Open the chat": "Ouvrir la conversation",
"Open the page again": "Rouvrir la page",
"Open the release page": "Ouvrir la page de la version",
"Or type an answer": "Ou saisissez une réponse",
"Outputs": "Sorties",
"Page": "Page",
@@ -1759,6 +1769,7 @@ const LEMBAS_I18N = {
"The numbers count this chat's own agent: 1 is the agent alone, with no subagents; Max 4 is the agent and up to 3 subagents. A subagent runs on the chat's model, or on another only when you name it in the chat.": "Les nombres comptent l’agent de la conversation : 1, c’est l’agent seul, sans sous-agents ; Max 4, c’est l’agent et jusqu’à 3 sous-agents. Un sous-agent utilise le modèle de la conversation, ou un autre seulement si vous le nommez dans la conversation.",
"The previous command": "La commande précédente",
"The previous command (Ctrl+Shift+↑)": "La commande précédente (Ctrl+Shift+↑)",
"The release that goes with the server's version. This is %(current)s.": "La version qui va avec celle du serveur. Celle-ci est la %(current)s.",
"The reply is ready.": "La réponse est prête.",
"The result is no longer there.": "Le résultat n'est plus là.",
"The server refused this computer's link: %(why)s": "Le serveur a refusé la liaison de cet ordinateur : %(why)s",
@@ -1819,6 +1830,7 @@ const LEMBAS_I18N = {
"You asked: “%(text)s”": "Votre demande : « %(text)s »",
"Your answer": "Votre réponse",
"Your files on the server, as the chats see them.": "Vos fichiers sur le serveur, tels que les conversations les voient.",
"Your server recommends LLeMbas Desktop %(version)s": "Votre serveur recommande LLeMbas Desktop %(version)s",
"a question": "une question",
"agent connecting…": "agent en connexion…",
"agent off": "agent arrêté",
@@ -2096,6 +2108,7 @@ const LEMBAS_I18N = {
"Open the activity panel": "A tevékenységpanel megnyitása",
"Open the chat": "A csevegés megnyitása",
"Open the page again": "Oldal újbóli megnyitása",
"Open the release page": "Kiadás oldalának megnyitása",
"Or type an answer": "Vagy írjon választ",
"Outputs": "Kimenetek",
"Page": "Oldal",
@@ -2224,6 +2237,7 @@ const LEMBAS_I18N = {
"The numbers count this chat's own agent: 1 is the agent alone, with no subagents; Max 4 is the agent and up to 3 subagents. A subagent runs on the chat's model, or on another only when you name it in the chat.": "A számokba a beszélgetés saját ügynöke is beleszámít: az 1 maga az ügynök, alügynökök nélkül; a Max. 4 az ügynök és legfeljebb 3 alügynök. Az alügynök a beszélgetés modelljén fut, másikon csak akkor, ha megnevezi a beszélgetésben.",
"The previous command": "Előző parancs",
"The previous command (Ctrl+Shift+↑)": "Előző parancs (Ctrl+Shift+↑)",
"The release that goes with the server's version. This is %(current)s.": "A szerver verziójához tartozó kiadás. Ez a %(current)s.",
"The reply is ready.": "A válasz kész.",
"The result is no longer there.": "Az eredmény már nincs meg.",
"The server refused this computer's link: %(why)s": "A szerver elutasította ennek a számítógépnek a kapcsolatát: %(why)s",
@@ -2284,6 +2298,7 @@ const LEMBAS_I18N = {
"You asked: “%(text)s”": "Az Ön kérése: „%(text)s”",
"Your answer": "Az Ön válasza",
"Your files on the server, as the chats see them.": "Az Ön fájljai a szerveren, ahogy a beszélgetések látják őket.",
"Your server recommends LLeMbas Desktop %(version)s": "A szervere a LLeMbas Desktop %(version)s verziót ajánlja",
"a question": "egy kérdés",
"agent connecting…": "ügynök csatlakozik…",
"agent off": "ügynök kikapcsolva",
@@ -2561,6 +2576,7 @@ const LEMBAS_I18N = {
"Open the activity panel": "Apri il pannello attività",
"Open the chat": "Apri la chat",
"Open the page again": "Riapri la pagina",
"Open the release page": "Apri la pagina della versione",
"Or type an answer": "Oppure scriva una risposta",
"Outputs": "Risultati",
"Page": "Pagina",
@@ -2689,6 +2705,7 @@ const LEMBAS_I18N = {
"The numbers count this chat's own agent: 1 is the agent alone, with no subagents; Max 4 is the agent and up to 3 subagents. A subagent runs on the chat's model, or on another only when you name it in the chat.": "I numeri contano anche l’agente della chat: 1 è l’agente da solo, senza sottoagenti; Max 4 è l’agente più fino a 3 sottoagenti. Un sottoagente usa il modello della chat, o un altro solo se lo nomini nella chat.",
"The previous command": "Il comando precedente",
"The previous command (Ctrl+Shift+↑)": "Il comando precedente (Ctrl+Shift+↑)",
"The release that goes with the server's version. This is %(current)s.": "La versione che va con quella del server. Questa è la %(current)s.",
"The reply is ready.": "La risposta è pronta.",
"The result is no longer there.": "Il risultato non c’è più.",
"The server refused this computer's link: %(why)s": "Il server ha rifiutato il collegamento di questo computer: %(why)s",
@@ -2749,6 +2766,7 @@ const LEMBAS_I18N = {
"You asked: “%(text)s”": "Hai chiesto: «%(text)s»",
"Your answer": "La sua risposta",
"Your files on the server, as the chats see them.": "I tuoi file sul server, come li vedono le chat.",
"Your server recommends LLeMbas Desktop %(version)s": "Il tuo server consiglia LLeMbas Desktop %(version)s",
"a question": "una domanda",
"agent connecting…": "agente in collegamento…",
"agent off": "agente spento",
@@ -3026,6 +3044,7 @@ const LEMBAS_I18N = {
"Open the activity panel": "Otwórz panel aktywności",
"Open the chat": "Otwórz czat",
"Open the page again": "Otwórz stronę ponownie",
"Open the release page": "Otwórz stronę wydania",
"Or type an answer": "Albo wpisz odpowiedź",
"Outputs": "Wyniki",
"Page": "Strona",
@@ -3154,6 +3173,7 @@ const LEMBAS_I18N = {
"The numbers count this chat's own agent: 1 is the agent alone, with no subagents; Max 4 is the agent and up to 3 subagents. A subagent runs on the chat's model, or on another only when you name it in the chat.": "Liczby obejmują własnego agenta czatu: 1 to sam agent, bez podagentów; Maks 4 to agent i do 3 podagentów. Podagent działa na modelu czatu, na innym tylko wtedy, gdy wskażesz go w czacie.",
"The previous command": "Poprzednie polecenie",
"The previous command (Ctrl+Shift+↑)": "Poprzednie polecenie (Ctrl+Shift+↑)",
"The release that goes with the server's version. This is %(current)s.": "Wydanie pasujące do wersji serwera. To jest %(current)s.",
"The reply is ready.": "Odpowiedź jest gotowa.",
"The result is no longer there.": "Wyniku już nie ma.",
"The server refused this computer's link: %(why)s": "Serwer odrzucił połączenie tego komputera: %(why)s",
@@ -3214,6 +3234,7 @@ const LEMBAS_I18N = {
"You asked: “%(text)s”": "Twoja prośba: „%(text)s”",
"Your answer": "Twoja odpowiedź",
"Your files on the server, as the chats see them.": "Twoje pliki na serwerze, tak jak widzą je czaty.",
"Your server recommends LLeMbas Desktop %(version)s": "Twój serwer zaleca LLeMbas Desktop %(version)s",
"a question": "pytanie",
"agent connecting…": "agent łączy się…",
"agent off": "agent wyłączony",
@@ -3491,6 +3512,7 @@ const LEMBAS_I18N = {
"Open the activity panel": "Otvoriť panel aktivity",
"Open the chat": "Otvoriť konverzáciu",
"Open the page again": "Otvoriť stránku znova",
"Open the release page": "Otvoriť stránku vydania",
"Or type an answer": "Alebo napíšte odpoveď",
"Outputs": "Výstupy",
"Page": "Stránka",
@@ -3619,6 +3641,7 @@ const LEMBAS_I18N = {
"The numbers count this chat's own agent: 1 is the agent alone, with no subagents; Max 4 is the agent and up to 3 subagents. A subagent runs on the chat's model, or on another only when you name it in the chat.": "Čísla počítajú aj vlastného agenta konverzácie: 1 je agent sám, bez podagentov; Max 4 je agent a až 3 podagenti. Podagent beží na modeli konverzácie, na inom len vtedy, keď ho v konverzácii pomenujete.",
"The previous command": "Predchádzajúci príkaz",
"The previous command (Ctrl+Shift+↑)": "Predchádzajúci príkaz (Ctrl+Shift+↑)",
"The release that goes with the server's version. This is %(current)s.": "Vydanie, ktoré patrí k verzii servera. Toto je %(current)s.",
"The reply is ready.": "Odpoveď je hotová.",
"The result is no longer there.": "Výsledok už tu nie je.",
"The server refused this computer's link: %(why)s": "Server odmietol prepojenie tohto počítača: %(why)s",
@@ -3679,6 +3702,7 @@ const LEMBAS_I18N = {
"You asked: “%(text)s”": "Požiadali ste: „%(text)s“",
"Your answer": "Vaša odpoveď",
"Your files on the server, as the chats see them.": "Vaše súbory na serveri, tak ako ich vidia konverzácie.",
"Your server recommends LLeMbas Desktop %(version)s": "Váš server odporúča LLeMbas Desktop %(version)s",
"a question": "otázka",
"agent connecting…": "agent sa pripája…",
"agent off": "agent vypnutý",
+58 -1
View File
@@ -4,7 +4,7 @@
// this release.
import { $, h, clear, icon, ICONS } from "./dom.js"
import { invoke, listen } from "./bridge.js"
import { invoke, listen, get, openLink } from "./bridge.js"
import { agentBlock, onAgentChange, link } from "./agent.js"
import { localTheme, chooseTheme, accountTheme, accountThemes, chosenLanguage, chooseLanguage, accountLanguage } from "./look.js"
import { why } from "./bridge.js"
@@ -136,6 +136,7 @@ export function renderSettings(s) {
),
)
const advised = recommendation(s)
box.append(
section(
"about",
@@ -145,8 +146,64 @@ export function renderSettings(s) {
s.update ? t("LLeMbas %(version)s is available (this is %(current)s)", { version: s.update, current: s.version }) : "",
h("button", { type: "button", class: "btn btn--sm", text: s.update ? t("Install LLeMbas %(version)s…", { version: s.update }) : t("Check for updates…"), onclick: () => invoke("update_app") }),
),
advised
? line(
t("Your server recommends LLeMbas Desktop %(version)s", { version: advised.version }),
t("The release that goes with the server's version. This is %(current)s.", { current: s.version }),
h("button", { type: "button", class: "btn btn--sm", text: t("Open the release page"), onclick: () => openLink(advised.page) }),
)
: null,
),
)
if (s.account && appsFor !== s.server) askApps(s.server)
}
// --- The release the server recommends (GET /apps) --------------------------------------------------
//
// GET /apps { server: { version, channel }, apps: { desktop: { version, tag, channel, page } | null } }
//
// Shown when it is newer than this app. A stable install is never offered a beta; a beta install
// may be. Only the project's own release pages are opened.
let apps = null // the server's recommendation; null: none (an older server, or nothing newer)
let appsFor = null // the server it was asked of
const RELEASES = "https://github.com/LLeMbas/LLeMbas-Desktop/releases/tag/"
const VERSION = /^v?(\d+)\.(\d+)\.(\d+)(?:-beta\.(\d+))?$/
/** A sortable key for `X.Y.Z` / `X.Y.Z-beta.N` (a release above its betas); null for anything else. */
export function versionKey(text) {
const m = VERSION.exec(String(text || "").trim())
return m ? [+m[1], +m[2], +m[3], m[4] === undefined ? Infinity : +m[4]] : null
}
function newer(a, b) {
for (let i = 0; i < 4; i++) if (a[i] !== b[i]) return a[i] > b[i]
return false
}
async function askApps(server) {
appsFor = server
apps = null
try {
const r = (await get("/apps"))?.apps?.desktop || null
if (appsFor === server) apps = r
} catch {
apps = null
}
if (!$("settings").hidden) renderSettings(current())
}
/** The recommended release, where it is newer than this one and on a channel this install takes. */
function recommendation(s) {
if (!apps) return null
const mine = versionKey(s.version)
const theirs = versionKey(apps.version)
if (!mine || !theirs) return null
if (theirs[3] !== Infinity && mine[3] === Infinity) return null
if (!newer(theirs, mine)) return null
const page = String(apps.page || "")
if (!page.startsWith(RELEASES) || !/^[A-Za-z0-9._-]+$/.test(page.slice(RELEASES.length))) return null
return { version: apps.version, page }
}
let lookError = ""