feat(t-paliad-151) frontend: friendly errors for remote-Paliadin codes

Extends the SSE error switch in frontend/src/client/paliadin.ts'
friendlyErrorMessage to map four new error codes from RemotePaliadin
Service into localised messages:

- mriver_unreachable: mRiver is offline / paliadin-shim unreachable
  (DE: "mRiver ist offline — Paliadin nicht erreichbar. Mach mRiver an,
  oder nutze Paliadin lokal mit ./paliad."
   EN: "mRiver is offline — Paliadin can't reach it. Wake mRiver, or
  run Paliadin locally with ./paliad.")
- shim_auth_failed: SSH key / authorized_keys mismatch (Permission
  denied)
- shim_error / bootstrap_failed: generic remote-shim failure
- timeout: Claude didn't write the response file in 60 s

Adds the matching i18n keys (DE + EN) plus the type-union entries in
i18n-keys.ts so the t() typecheck stays sound. The old codes
(tmux_unavailable, connection_lost, upstream) are unchanged — local-PoC
deployments keep their existing UX.

Frontend `bun run build` clean: 1886 keys (unchanged sync).

Refs m/paliad#12
This commit is contained in:
m
2026-05-08 02:19:48 +02:00
parent 68c56ea920
commit e4110cf2db
3 changed files with 30 additions and 2 deletions

View File

@@ -1558,6 +1558,10 @@ const translations: Record<Lang, Record<string, string>> = {
"paliadin.stop": "Stop",
"paliadin.reset": "Neue Unterhaltung",
"paliadin.error.local_only": "Paliadin läuft nur lokal. Diese Instanz hat kein tmux/claude installiert — lokal mit ./paliad starten.",
"paliadin.error.mriver_unreachable": "mRiver ist offline — Paliadin nicht erreichbar. Mach mRiver an, oder nutze Paliadin lokal mit ./paliad.",
"paliadin.error.shim_auth_failed": "Paliadin-Authentifizierung fehlgeschlagen. SSH-Schlüssel oder Berechtigung auf mRiver prüfen.",
"paliadin.error.shim_error": "Paliadin-Fehler auf mRiver. tmux/claude-Pane prüfen.",
"paliadin.error.timeout": "Paliadin antwortet nicht (Timeout 60s). Nochmal versuchen.",
"paliadin.error.connection_lost": "Verbindung verloren.",
"paliadin.error.upstream": "Fehler beim Senden.",
"nav.admin.paliadin": "Paliadin Monitor",
@@ -3553,6 +3557,10 @@ const translations: Record<Lang, Record<string, string>> = {
"paliadin.stop": "Stop",
"paliadin.reset": "New conversation",
"paliadin.error.local_only": "Paliadin only runs locally. This instance has no tmux/claude installed — start it locally via ./paliad.",
"paliadin.error.mriver_unreachable": "mRiver is offline — Paliadin can't reach it. Wake mRiver, or run Paliadin locally with ./paliad.",
"paliadin.error.shim_auth_failed": "Paliadin auth failed. Check the SSH key or authorized_keys on mRiver.",
"paliadin.error.shim_error": "Paliadin error on mRiver. Check the tmux/claude pane.",
"paliadin.error.timeout": "Paliadin didn't respond in time (60s). Try again.",
"paliadin.error.connection_lost": "Connection lost.",
"paliadin.error.upstream": "Send failed.",
"nav.admin.paliadin": "Paliadin Monitor",

View File

@@ -210,8 +210,24 @@ function friendlyErrorMessage(data: unknown): string {
}
try {
const parsed = JSON.parse(data) as { code?: string };
if (parsed.code === "tmux_unavailable") {
switch (parsed.code) {
case "tmux_unavailable":
// Local PoC path: paliad is running on a host without tmux/claude
// (typically the legacy laptop-only build).
return t("paliadin.error.local_only");
case "mriver_unreachable":
// t-paliad-151: prod path's mRiver is offline (laptop asleep, off
// tailnet, or paliadin-shim missing).
return t("paliadin.error.mriver_unreachable");
case "shim_auth_failed":
// SSH key wrong or authorized_keys drifted.
return t("paliadin.error.shim_auth_failed");
case "shim_error":
case "bootstrap_failed":
// Generic remote shim failure or system-prompt bootstrap error.
return t("paliadin.error.shim_error");
case "timeout":
return t("paliadin.error.timeout");
}
} catch {
// Not JSON — fall through to the generic connection-lost message

View File

@@ -1423,6 +1423,10 @@ export type I18nKey =
| "paliadin.empty"
| "paliadin.error.connection_lost"
| "paliadin.error.local_only"
| "paliadin.error.mriver_unreachable"
| "paliadin.error.shim_auth_failed"
| "paliadin.error.shim_error"
| "paliadin.error.timeout"
| "paliadin.error.upstream"
| "paliadin.heading"
| "paliadin.input.placeholder"