+
+ {/* Favorite agents for the cycle-favorite gesture. */}
+
+
+ {t("floatingBall.favoriteAgents")}
+
+
+
+ {t("floatingBall.favoriteAgentsHint")}
+
+
{/* ===== Chat content width ===== */}
diff --git a/src/hooks/use-appearance.ts b/src/hooks/use-appearance.ts
index 7d08bece29..ac2730b1cf 100644
--- a/src/hooks/use-appearance.ts
+++ b/src/hooks/use-appearance.ts
@@ -4,6 +4,7 @@ import { useContext } from "react"
import {
AppearanceContext,
ChatAnimationsContext,
+ DEFAULT_FLOATING_BALL_SIZE,
} from "@/components/appearance-provider"
import {
applyChatContentWidth,
@@ -56,6 +57,13 @@ export function useFloatingBall() {
setFloatingBallEnabled: ctx?.setFloatingBallEnabled ?? (() => {}),
floatingBallPosition: ctx?.floatingBallPosition ?? null,
setFloatingBallPosition: ctx?.setFloatingBallPosition ?? (() => {}),
+ floatingBallBindings: ctx?.floatingBallBindings ?? {},
+ setFloatingBallBindings: ctx?.setFloatingBallBindings ?? (() => {}),
+ floatingBallSize: ctx?.floatingBallSize ?? DEFAULT_FLOATING_BALL_SIZE,
+ setFloatingBallSize: ctx?.setFloatingBallSize ?? (() => {}),
+ floatingBallFavoriteAgents: ctx?.floatingBallFavoriteAgents ?? [],
+ setFloatingBallFavoriteAgents:
+ ctx?.setFloatingBallFavoriteAgents ?? (() => {}),
}
}
diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json
index 670eea527d..bb16902416 100644
--- a/src/i18n/messages/ar.json
+++ b/src/i18n/messages/ar.json
@@ -245,7 +245,73 @@
"sectionDescription": "كرة قابلة للسحب فوق مساحة العمل تحوّل السحب إلى اختصارات، مصممة للهاتف حيث لا توجد لوحة مفاتيح.",
"enable": "إظهار الكرة العائمة",
"hint": "اسحب للتحريك، اسحب بسرعة لإيماءة، اضغط مطوّلاً للوحة وقائمة الإيماءات.",
- "resetPosition": "إعادة تعيين الموضع"
+ "resetPosition": "إعادة تعيين الموضع",
+ "ballSize": "حجم الكرة",
+ "sizeSmall": "صغير",
+ "sizeMedium": "متوسط",
+ "sizeLarge": "كبير",
+ "gestureBindings": "ربط الإيماءات",
+ "bindingCleared": "غير مربوط",
+ "favoriteAgents": "الوكلاء المفضلون",
+ "favoriteAgentsHint": "اختر 2-3 وكلاء للتنقل بينهم بإيماءة المفضلين.",
+ "favoriteAgentsEmpty": "لا يوجد وكلاء متاحون",
+ "panelTitle": "إجراءات سريعة"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "تصغير",
"zoomReset": "إعادة تعيين التكبير",
"stopGenerating": "إيقاف التوليد",
- "openSettings": "الإعدادات"
+ "openSettings": "الإعدادات",
+ "openTodos": "المهام",
+ "openTodosNew": "مهمة جديدة",
+ "openAutomations": "الأتمتة",
+ "openCanvas": "اللوحة",
+ "openAgents": "الوكلاء",
+ "openSystemAdmin": "إدارة النظام",
+ "renameConversation": "إعادة تسمية المحادثة",
+ "openSessionFolder": "ملفات الجلسة",
+ "cycleAgent": "الوكيل التالي",
+ "cycleFavoriteAgent": "الوكلاء المفضلون"
},
"gestures": {
"tap": "نقرة",
@@ -7374,7 +7450,22 @@
"leftThenRight": "يسار ثم يمين",
"rightThenLeft": "يمين ثم يسار",
"upLeftThenDown": "أعلى اليسار ثم أسفل",
- "upRightThenDown": "أعلى اليمين ثم أسفل"
- }
+ "upRightThenDown": "أعلى اليمين ثم أسفل",
+ "down": "اسحب لأسفل",
+ "downLeft": "أسفل-يسار",
+ "downRight": "أسفل-يمين",
+ "downUp": "أسفل ثم أعلى",
+ "upThenDownRight": "أعلى ثم أسفل-يمين",
+ "downThenUpRight": "أسفل ثم أعلى-يمين",
+ "rightThenUp": "يمين ثم أعلى",
+ "rightThenDown": "يمين ثم أسفل",
+ "downThenRight": "أسفل ثم يمين",
+ "downThenLeft": "أسفل ثم يسار",
+ "downRightThenUp": "أسفل-يمين ثم أعلى",
+ "downLeftThenUp": "أسفل-يسار ثم أعلى",
+ "upLeftThenRight": "أعلى-يسار ثم يمين",
+ "upRightThenLeft": "أعلى-يمين ثم يسار"
+ },
+ "favoriteAgentsEmpty": "لا يوجد وكلاء متاحون"
}
}
diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json
index b761c3d26f..f1e38eb844 100644
--- a/src/i18n/messages/de.json
+++ b/src/i18n/messages/de.json
@@ -245,7 +245,73 @@
"sectionDescription": "Eine verschiebbare Kugel über dem Arbeitsbereich, die Wischgesten in Tastenkürzel verwandelt – gedacht für das Telefon ohne Tastatur.",
"enable": "Schwebekugel anzeigen",
"hint": "Ziehen zum Verschieben, schnelles Wischen für eine Geste, langes Drücken für Panel und Gestenübersicht.",
- "resetPosition": "Position zurücksetzen"
+ "resetPosition": "Position zurücksetzen",
+ "ballSize": "Kugelgröße",
+ "sizeSmall": "Klein",
+ "sizeMedium": "Mittel",
+ "sizeLarge": "Groß",
+ "gestureBindings": "Gestenzuordnung",
+ "bindingCleared": "Nicht zugewiesen",
+ "favoriteAgents": "Favoriten-Agenten",
+ "favoriteAgentsHint": "Wähle 2-3 Agenten, um sie mit dem Favoriten-Gest zu durchlaufen.",
+ "favoriteAgentsEmpty": "Keine Agenten verfügbar",
+ "panelTitle": "Schnellaktionen"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "Verkleinern",
"zoomReset": "Zoom zurücksetzen",
"stopGenerating": "Generierung stoppen",
- "openSettings": "Einstellungen"
+ "openSettings": "Einstellungen",
+ "openTodos": "Aufgaben",
+ "openTodosNew": "Neue Aufgabe",
+ "openAutomations": "Automatisierungen",
+ "openCanvas": "Canvas",
+ "openAgents": "Agenten",
+ "openSystemAdmin": "Systemverwaltung",
+ "renameConversation": "Unterhaltung umbenennen",
+ "openSessionFolder": "Sitzungsdateien",
+ "cycleAgent": "Nächster Agent",
+ "cycleFavoriteAgent": "Favoriten-Agenten"
},
"gestures": {
"tap": "Tippen",
@@ -7374,7 +7450,22 @@
"leftThenRight": "Links, dann rechts",
"rightThenLeft": "Rechts, dann links",
"upLeftThenDown": "Oben links, dann unten",
- "upRightThenDown": "Oben rechts, dann unten"
- }
+ "upRightThenDown": "Oben rechts, dann unten",
+ "down": "Nach unten",
+ "downLeft": "Unten-links",
+ "downRight": "Unten-rechts",
+ "downUp": "Unten, dann oben",
+ "upThenDownRight": "Oben, dann unten-re.",
+ "downThenUpRight": "Unten, dann oben-re.",
+ "rightThenUp": "Rechts, dann oben",
+ "rightThenDown": "Rechts, dann unten",
+ "downThenRight": "Unten, dann rechts",
+ "downThenLeft": "Unten, dann links",
+ "downRightThenUp": "Unten-re., dann oben",
+ "downLeftThenUp": "Unten-li., dann oben",
+ "upLeftThenRight": "Oben-li., dann rechts",
+ "upRightThenLeft": "Oben-re., dann links"
+ },
+ "favoriteAgentsEmpty": "Keine Agenten verfügbar"
}
}
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 40dddea163..4d9f43bf03 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -245,7 +245,73 @@
"sectionDescription": "A draggable ball over the workspace that turns swipes into shortcuts — built for the phone, where there is no keyboard.",
"enable": "Show floating ball",
"hint": "Drag to move; swipe quickly for a gesture; long press for the panel and cheat sheet.",
- "resetPosition": "Reset position"
+ "resetPosition": "Reset position",
+ "ballSize": "Ball size",
+ "sizeSmall": "Small",
+ "sizeMedium": "Medium",
+ "sizeLarge": "Large",
+ "gestureBindings": "Gesture bindings",
+ "bindingCleared": "Unbound",
+ "favoriteAgents": "Favorite agents",
+ "favoriteAgentsHint": "Pick 2-3 agents to cycle through with the favorite-agents gesture.",
+ "favoriteAgentsEmpty": "No available agents",
+ "panelTitle": "Quick actions"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "Zoom out",
"zoomReset": "Reset zoom",
"stopGenerating": "Stop generating",
- "openSettings": "Settings"
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
},
"gestures": {
"tap": "Tap",
@@ -7374,7 +7450,22 @@
"leftThenRight": "Left, then right",
"rightThenLeft": "Right, then left",
"upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down"
- }
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "favoriteAgentsEmpty": "No available agents"
}
}
diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json
index 5a552bfd2e..1a7fdba587 100644
--- a/src/i18n/messages/es.json
+++ b/src/i18n/messages/es.json
@@ -245,7 +245,73 @@
"sectionDescription": "Una bola arrastrable sobre el espacio de trabajo que convierte los deslizamientos en atajos, pensada para el teléfono, donde no hay teclado.",
"enable": "Mostrar bola flotante",
"hint": "Arrastra para mover, desliza rápido para un gesto, mantén pulsado para el panel y la lista de gestos.",
- "resetPosition": "Restablecer posición"
+ "resetPosition": "Restablecer posición",
+ "ballSize": "Tamaño de la bola",
+ "sizeSmall": "Pequeño",
+ "sizeMedium": "Mediano",
+ "sizeLarge": "Grande",
+ "gestureBindings": "Asignación de gestos",
+ "bindingCleared": "Sin asignar",
+ "favoriteAgents": "Agentes favoritos",
+ "favoriteAgentsHint": "Elige 2-3 agentes para alternar con el gesto de favoritos.",
+ "favoriteAgentsEmpty": "No hay agentes disponibles",
+ "panelTitle": "Acciones rápidas"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "Alejar",
"zoomReset": "Restablecer zoom",
"stopGenerating": "Detener la generación",
- "openSettings": "Ajustes"
+ "openSettings": "Ajustes",
+ "openTodos": "Tareas",
+ "openTodosNew": "Nueva tarea",
+ "openAutomations": "Automatizaciones",
+ "openCanvas": "Lienzo",
+ "openAgents": "Agentes",
+ "openSystemAdmin": "Administración",
+ "renameConversation": "Renombrar conversación",
+ "openSessionFolder": "Archivos de sesión",
+ "cycleAgent": "Siguiente agente",
+ "cycleFavoriteAgent": "Agentes favoritos"
},
"gestures": {
"tap": "Toque",
@@ -7374,7 +7450,22 @@
"leftThenRight": "Izquierda y luego derecha",
"rightThenLeft": "Derecha y luego izquierda",
"upLeftThenDown": "Arriba a la izquierda y luego abajo",
- "upRightThenDown": "Arriba a la derecha y luego abajo"
- }
+ "upRightThenDown": "Arriba a la derecha y luego abajo",
+ "down": "Deslizar abajo",
+ "downLeft": "Abajo-izq.",
+ "downRight": "Abajo-der.",
+ "downUp": "Abajo, luego arriba",
+ "upThenDownRight": "Arriba, luego abajo-der.",
+ "downThenUpRight": "Abajo, luego arriba-der.",
+ "rightThenUp": "Derecha, luego arriba",
+ "rightThenDown": "Derecha, luego abajo",
+ "downThenRight": "Abajo, luego derecha",
+ "downThenLeft": "Abajo, luego izquierda",
+ "downRightThenUp": "Abajo-der., luego arriba",
+ "downLeftThenUp": "Abajo-izq., luego arriba",
+ "upLeftThenRight": "Arriba-izq., luego derecha",
+ "upRightThenLeft": "Arriba-der., luego izquierda"
+ },
+ "favoriteAgentsEmpty": "No hay agentes disponibles"
}
}
diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json
index cfe3b4a4ce..cfa49392eb 100644
--- a/src/i18n/messages/fr.json
+++ b/src/i18n/messages/fr.json
@@ -245,7 +245,73 @@
"sectionDescription": "Une boule déplaçable au-dessus de l’espace de travail qui transforme les balayages en raccourcis — pensée pour le téléphone, où il n’y a pas de clavier.",
"enable": "Afficher la boule flottante",
"hint": "Faites glisser pour déplacer, balayez rapidement pour un geste, appuyez longuement pour le panneau et la liste des gestes.",
- "resetPosition": "Réinitialiser la position"
+ "resetPosition": "Réinitialiser la position",
+ "ballSize": "Taille de la bille",
+ "sizeSmall": "Petite",
+ "sizeMedium": "Moyenne",
+ "sizeLarge": "Grande",
+ "gestureBindings": "Affectation des gestes",
+ "bindingCleared": "Non attribué",
+ "favoriteAgents": "Agents favoris",
+ "favoriteAgentsHint": "Choisissez 2-3 agents à parcourir avec le geste des favoris.",
+ "favoriteAgentsEmpty": "Aucun agent disponible",
+ "panelTitle": "Actions rapides"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "Zoom arrière",
"zoomReset": "Réinitialiser le zoom",
"stopGenerating": "Arrêter la génération",
- "openSettings": "Paramètres"
+ "openSettings": "Paramètres",
+ "openTodos": "Tâches",
+ "openTodosNew": "Nouvelle tâche",
+ "openAutomations": "Automatisations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "Administration",
+ "renameConversation": "Renommer la conversation",
+ "openSessionFolder": "Fichiers de session",
+ "cycleAgent": "Agent suivant",
+ "cycleFavoriteAgent": "Agents favoris"
},
"gestures": {
"tap": "Appui",
@@ -7374,7 +7450,22 @@
"leftThenRight": "Gauche, puis droite",
"rightThenLeft": "Droite, puis gauche",
"upLeftThenDown": "Haut-gauche, puis bas",
- "upRightThenDown": "Haut-droite, puis bas"
- }
+ "upRightThenDown": "Haut-droite, puis bas",
+ "down": "Balayer vers le bas",
+ "downLeft": "Bas-gauche",
+ "downRight": "Bas-droite",
+ "downUp": "Bas, puis haut",
+ "upThenDownRight": "Haut, puis bas-dr.",
+ "downThenUpRight": "Bas, puis haut-dr.",
+ "rightThenUp": "Droite, puis haut",
+ "rightThenDown": "Droite, puis bas",
+ "downThenRight": "Bas, puis droite",
+ "downThenLeft": "Bas, puis gauche",
+ "downRightThenUp": "Bas-dr., puis haut",
+ "downLeftThenUp": "Bas-g., puis haut",
+ "upLeftThenRight": "Haut-g., puis droite",
+ "upRightThenLeft": "Haut-dr., puis gauche"
+ },
+ "favoriteAgentsEmpty": "Aucun agent disponible"
}
}
diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json
index a915251370..25964435b8 100644
--- a/src/i18n/messages/ja.json
+++ b/src/i18n/messages/ja.json
@@ -245,7 +245,73 @@
"sectionDescription": "ワークスペース上に置くドラッグ可能なボール。スワイプをショートカットに変えます。キーボードのないスマートフォン向けです。",
"enable": "フローティングボールを表示",
"hint": "ドラッグで移動、素早いスワイプでジェスチャー、長押しでパネルとジェスチャー一覧を開きます。",
- "resetPosition": "位置をリセット"
+ "resetPosition": "位置をリセット",
+ "ballSize": "ボールサイズ",
+ "sizeSmall": "小",
+ "sizeMedium": "中",
+ "sizeLarge": "大",
+ "gestureBindings": "ジェスチャー割り当て",
+ "bindingCleared": "未割り当て",
+ "favoriteAgents": "お気に入りエージェント",
+ "favoriteAgentsHint": "2〜3個のエージェントを選ぶと、お気に入りジェスチャーで切り替えられます。",
+ "favoriteAgentsEmpty": "利用可能なエージェントがありません",
+ "panelTitle": "クイック操作"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "縮小",
"zoomReset": "ズームをリセット",
"stopGenerating": "生成を停止",
- "openSettings": "設定"
+ "openSettings": "設定",
+ "openTodos": "ToDo",
+ "openTodosNew": "ToDo作成",
+ "openAutomations": "オートメーション",
+ "openCanvas": "キャンバス",
+ "openAgents": "エージェント",
+ "openSystemAdmin": "システム管理",
+ "renameConversation": "会話名を変更",
+ "openSessionFolder": "セッションファイル",
+ "cycleAgent": "次のエージェント",
+ "cycleFavoriteAgent": "お気に入りエージェント"
},
"gestures": {
"tap": "タップ",
@@ -7374,7 +7450,22 @@
"leftThenRight": "左→右",
"rightThenLeft": "右→左",
"upLeftThenDown": "左上→下",
- "upRightThenDown": "右上→下"
- }
+ "upRightThenDown": "右上→下",
+ "down": "下スワイプ",
+ "downLeft": "左下",
+ "downRight": "右下",
+ "downUp": "下から上",
+ "upThenDownRight": "上から右下",
+ "downThenUpRight": "下から右上",
+ "rightThenUp": "右から上",
+ "rightThenDown": "右から下",
+ "downThenRight": "下から右",
+ "downThenLeft": "下から左",
+ "downRightThenUp": "右下から上",
+ "downLeftThenUp": "左下から上",
+ "upLeftThenRight": "左上から右",
+ "upRightThenLeft": "右上から左"
+ },
+ "favoriteAgentsEmpty": "利用可能なエージェントがありません"
}
}
diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json
index 01214e8f7c..a430f35e7a 100644
--- a/src/i18n/messages/ko.json
+++ b/src/i18n/messages/ko.json
@@ -245,7 +245,73 @@
"sectionDescription": "작업 공간 위의 드래그 가능한 볼로, 스와이프를 단축키로 바꿉니다. 키보드가 없는 휴대폰을 위한 기능입니다.",
"enable": "플로팅 볼 표시",
"hint": "드래그로 이동, 빠른 스와이프로 제스처, 길게 눌러 패널과 제스처 목록을 엽니다.",
- "resetPosition": "위치 초기화"
+ "resetPosition": "위치 초기화",
+ "ballSize": "공 크기",
+ "sizeSmall": "작게",
+ "sizeMedium": "보통",
+ "sizeLarge": "크게",
+ "gestureBindings": "제스처 바인딩",
+ "bindingCleared": "미지정",
+ "favoriteAgents": "즐겨쓰는 에이전트",
+ "favoriteAgentsHint": "2~3개의 에이전트를 선택하면 즐겨쓰기 제스처로 순환 전환됩니다.",
+ "favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다",
+ "panelTitle": "빠른 작업"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "축소",
"zoomReset": "확대/축소 초기화",
"stopGenerating": "생성 중지",
- "openSettings": "설정"
+ "openSettings": "설정",
+ "openTodos": "할 일",
+ "openTodosNew": "새 할 일",
+ "openAutomations": "자동화",
+ "openCanvas": "캔버스",
+ "openAgents": "에이전트",
+ "openSystemAdmin": "시스템 관리",
+ "renameConversation": "대화 이름 바꾸기",
+ "openSessionFolder": "세션 파일",
+ "cycleAgent": "다음 에이전트",
+ "cycleFavoriteAgent": "즐겨쓰는 에이전트"
},
"gestures": {
"tap": "탭",
@@ -7374,7 +7450,22 @@
"leftThenRight": "왼쪽 → 오른쪽",
"rightThenLeft": "오른쪽 → 왼쪽",
"upLeftThenDown": "왼쪽 위 → 아래",
- "upRightThenDown": "오른쪽 위 → 아래"
- }
+ "upRightThenDown": "오른쪽 위 → 아래",
+ "down": "아래로",
+ "downLeft": "왼쪽 아래",
+ "downRight": "오른쪽 아래",
+ "downUp": "아래→위",
+ "upThenDownRight": "위→오른아래",
+ "downThenUpRight": "아래→오른위",
+ "rightThenUp": "오른→위",
+ "rightThenDown": "오른→아래",
+ "downThenRight": "아래→오른",
+ "downThenLeft": "아래→왼",
+ "downRightThenUp": "오른아래→위",
+ "downLeftThenUp": "왼아래→위",
+ "upLeftThenRight": "왼위→오른",
+ "upRightThenLeft": "오른위→왼"
+ },
+ "favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다"
}
}
diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json
index 3d99db6a5a..01de443c45 100644
--- a/src/i18n/messages/pt.json
+++ b/src/i18n/messages/pt.json
@@ -245,7 +245,73 @@
"sectionDescription": "Uma bola arrastável sobre o espaço de trabalho que transforma deslizes em atalhos — feita para o telefone, onde não há teclado.",
"enable": "Mostrar bola flutuante",
"hint": "Arraste para mover, deslize rápido para um gesto, toque e segure para o painel e a lista de gestos.",
- "resetPosition": "Redefinir posição"
+ "resetPosition": "Redefinir posição",
+ "ballSize": "Tamanho da bola",
+ "sizeSmall": "Pequeno",
+ "sizeMedium": "Médio",
+ "sizeLarge": "Grande",
+ "gestureBindings": "Atribuição de gestos",
+ "bindingCleared": "Sem atribuição",
+ "favoriteAgents": "Agentes favoritos",
+ "favoriteAgentsHint": "Escolha 2-3 agentes para alternar com o gesto de favoritos.",
+ "favoriteAgentsEmpty": "Nenhum agente disponível",
+ "panelTitle": "Ações rápidas"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "Diminuir zoom",
"zoomReset": "Redefinir zoom",
"stopGenerating": "Parar geração",
- "openSettings": "Configurações"
+ "openSettings": "Configurações",
+ "openTodos": "Tarefas",
+ "openTodosNew": "Nova tarefa",
+ "openAutomations": "Automações",
+ "openCanvas": "Canvas",
+ "openAgents": "Agentes",
+ "openSystemAdmin": "Administração",
+ "renameConversation": "Renomear conversa",
+ "openSessionFolder": "Arquivos da sessão",
+ "cycleAgent": "Próximo agente",
+ "cycleFavoriteAgent": "Agentes favoritos"
},
"gestures": {
"tap": "Toque",
@@ -7374,7 +7450,22 @@
"leftThenRight": "Esquerda, depois direita",
"rightThenLeft": "Direita, depois esquerda",
"upLeftThenDown": "Cima-esquerda, depois baixo",
- "upRightThenDown": "Cima-direita, depois baixo"
- }
+ "upRightThenDown": "Cima-direita, depois baixo",
+ "down": "Deslizar para baixo",
+ "downLeft": "Baixo-esq.",
+ "downRight": "Baixo-dir.",
+ "downUp": "Baixo, depois cima",
+ "upThenDownRight": "Cima, depois baixo-dir.",
+ "downThenUpRight": "Baixo, depois cima-dir.",
+ "rightThenUp": "Direita, depois cima",
+ "rightThenDown": "Direita, depois baixo",
+ "downThenRight": "Baixo, depois direita",
+ "downThenLeft": "Baixo, depois esquerda",
+ "downRightThenUp": "Baixo-dir., depois cima",
+ "downLeftThenUp": "Baixo-esq., depois cima",
+ "upLeftThenRight": "Cima-esq., depois direita",
+ "upRightThenLeft": "Cima-dir., depois esquerda"
+ },
+ "favoriteAgentsEmpty": "Nenhum agente disponível"
}
}
diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json
index 6155947c3e..9e2d16d906 100644
--- a/src/i18n/messages/zh-CN.json
+++ b/src/i18n/messages/zh-CN.json
@@ -245,7 +245,73 @@
"sectionDescription": "工作区上的可拖动悬浮球,把滑动手势变成快捷键——为没有键盘的手机而设。",
"enable": "显示悬浮球",
"hint": "拖动可移动;快速滑动触发手势;长按打开面板与手势表。",
- "resetPosition": "重置位置"
+ "resetPosition": "重置位置",
+ "ballSize": "球体大小",
+ "sizeSmall": "小",
+ "sizeMedium": "中",
+ "sizeLarge": "大",
+ "gestureBindings": "手势绑定",
+ "bindingCleared": "未绑定",
+ "favoriteAgents": "常用智能体",
+ "favoriteAgentsHint": "选择 2-3 个智能体,供「常用智能体」手势循环快切。",
+ "favoriteAgentsEmpty": "暂无可用智能体",
+ "panelTitle": "快捷操作"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "缩小",
"zoomReset": "重置缩放",
"stopGenerating": "停止生成",
- "openSettings": "设置"
+ "openSettings": "设置",
+ "openTodos": "待办任务",
+ "openTodosNew": "新建待办",
+ "openAutomations": "自动化",
+ "openCanvas": "无限画布",
+ "openAgents": "智能体",
+ "openSystemAdmin": "系统管理",
+ "renameConversation": "重命名会话",
+ "openSessionFolder": "会话文件",
+ "cycleAgent": "下一个智能体",
+ "cycleFavoriteAgent": "常用智能体"
},
"gestures": {
"tap": "单击",
@@ -7374,7 +7450,22 @@
"leftThenRight": "左滑后右滑",
"rightThenLeft": "右滑后左滑",
"upLeftThenDown": "左上滑后下滑",
- "upRightThenDown": "右上滑后下滑"
- }
+ "upRightThenDown": "右上滑后下滑",
+ "down": "下滑",
+ "downLeft": "左下",
+ "downRight": "右下",
+ "downUp": "下再上",
+ "upThenDownRight": "上再右下",
+ "downThenUpRight": "下再右上",
+ "rightThenUp": "右再上",
+ "rightThenDown": "右再下",
+ "downThenRight": "下再右",
+ "downThenLeft": "下再左",
+ "downRightThenUp": "右下再上",
+ "downLeftThenUp": "左下再上",
+ "upLeftThenRight": "左上再右",
+ "upRightThenLeft": "右上再左"
+ },
+ "favoriteAgentsEmpty": "暂无可用智能体"
}
}
diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json
index edb89163ab..bc88edf1ff 100644
--- a/src/i18n/messages/zh-TW.json
+++ b/src/i18n/messages/zh-TW.json
@@ -245,7 +245,73 @@
"sectionDescription": "工作區上的可拖動懸浮球,把滑動手勢變成快捷鍵——為沒有鍵盤的手機而設。",
"enable": "顯示懸浮球",
"hint": "拖動可移動;快速滑動觸發手勢;長按打開面板與手勢表。",
- "resetPosition": "重設位置"
+ "resetPosition": "重設位置",
+ "ballSize": "球體大小",
+ "sizeSmall": "小",
+ "sizeMedium": "中",
+ "sizeLarge": "大",
+ "gestureBindings": "手勢綁定",
+ "bindingCleared": "未綁定",
+ "favoriteAgents": "常用代理人",
+ "favoriteAgentsHint": "選擇 2-3 個代理人,供「常用代理人」手勢循環快切。",
+ "favoriteAgentsEmpty": "暫無可用代理人",
+ "panelTitle": "快捷操作"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "Swipe left",
+ "right": "Swipe right",
+ "up": "Swipe up",
+ "upLeft": "Up-left",
+ "upRight": "Up-right",
+ "upThenLeft": "Up, then left",
+ "upThenRight": "Up, then right",
+ "upDown": "Up, then down",
+ "leftThenRight": "Left, then right",
+ "rightThenLeft": "Right, then left",
+ "upLeftThenDown": "Up-left, then down",
+ "upRightThenDown": "Up-right, then down",
+ "down": "Swipe down",
+ "downLeft": "Down-left",
+ "downRight": "Down-right",
+ "downUp": "Down, then up",
+ "upThenDownRight": "Up, then down-right",
+ "downThenUpRight": "Down, then up-right",
+ "rightThenUp": "Right, then up",
+ "rightThenDown": "Right, then down",
+ "downThenRight": "Down, then right",
+ "downThenLeft": "Down, then left",
+ "downRightThenUp": "Down-right, then up",
+ "downLeftThenUp": "Down-left, then up",
+ "upLeftThenRight": "Up-left, then right",
+ "upRightThenLeft": "Up-right, then left"
+ },
+ "actions": {
+ "newConversation": "New conversation",
+ "toggleSidebar": "Toggle sidebar",
+ "toggleSearch": "Search",
+ "toggleTerminal": "Toggle terminal",
+ "nextTab": "Next tab",
+ "prevTab": "Previous tab",
+ "reopenClosedTab": "Reopen closed tab",
+ "openFolder": "Open folder",
+ "zoomIn": "Zoom in",
+ "zoomOut": "Zoom out",
+ "zoomReset": "Reset zoom",
+ "stopGenerating": "Stop generating",
+ "openSettings": "Settings",
+ "openTodos": "To-dos",
+ "openTodosNew": "New to-do",
+ "openAutomations": "Automations",
+ "openCanvas": "Canvas",
+ "openAgents": "Agents",
+ "openSystemAdmin": "System admin",
+ "renameConversation": "Rename conversation",
+ "openSessionFolder": "Session files",
+ "cycleAgent": "Next agent",
+ "cycleFavoriteAgent": "Favorite agents"
}
},
"SystemSettings": {
@@ -7357,7 +7423,17 @@
"zoomOut": "縮小",
"zoomReset": "重設縮放",
"stopGenerating": "停止生成",
- "openSettings": "設定"
+ "openSettings": "設定",
+ "openTodos": "待辦任務",
+ "openTodosNew": "新建待辦",
+ "openAutomations": "自動化",
+ "openCanvas": "無限畫布",
+ "openAgents": "智慧代理人",
+ "openSystemAdmin": "系統管理",
+ "renameConversation": "重新命名會話",
+ "openSessionFolder": "會話檔案",
+ "cycleAgent": "下一個代理人",
+ "cycleFavoriteAgent": "常用代理人"
},
"gestures": {
"tap": "單擊",
@@ -7374,7 +7450,22 @@
"leftThenRight": "左滑後右滑",
"rightThenLeft": "右滑後左滑",
"upLeftThenDown": "左上滑後下滑",
- "upRightThenDown": "右上滑後下滑"
- }
+ "upRightThenDown": "右上滑後下滑",
+ "down": "下滑",
+ "downLeft": "左下",
+ "downRight": "右下",
+ "downUp": "下再上",
+ "upThenDownRight": "上再右下",
+ "downThenUpRight": "下再右上",
+ "rightThenUp": "右再上",
+ "rightThenDown": "右再下",
+ "downThenRight": "下再右",
+ "downThenLeft": "下再左",
+ "downRightThenUp": "右下再上",
+ "downLeftThenUp": "左下再上",
+ "upLeftThenRight": "左上再右",
+ "upRightThenLeft": "右上再左"
+ },
+ "favoriteAgentsEmpty": "暫無可用代理人"
}
}
diff --git a/src/lib/appearance-script.ts b/src/lib/appearance-script.ts
index de1ce4836c..4d9f2475d8 100644
--- a/src/lib/appearance-script.ts
+++ b/src/lib/appearance-script.ts
@@ -34,6 +34,12 @@ export const STORAGE_KEY_CHAT_CONTENT_WIDTH = "codeg-chat-content-width"
// 预水合——水合前根本不渲染球。
export const STORAGE_KEY_FLOATING_BALL_ENABLED = "codeg-floating-ball-enabled"
export const STORAGE_KEY_FLOATING_BALL_POSITION = "codeg-floating-ball-position"
+// 批v82:手势→动作绑定表(JSON,gesture → action | null;null 表示用户显式清除,
+// 与"缺 key 回退默认"语义不同)、球体三档大小、常用 agent 快切列表。同样无需预水合。
+export const STORAGE_KEY_FLOATING_BALL_BINDINGS = "codeg-floating-ball-bindings"
+export const STORAGE_KEY_FLOATING_BALL_SIZE = "codeg-floating-ball-size"
+export const STORAGE_KEY_FLOATING_BALL_FAVORITE_AGENTS =
+ "codeg-floating-ball-favorite-agents"
// 字体偏好(界面 / 编辑器 / 终端)。
// 只有界面字体需要 *_STACK(已解析的 CSS font-family 栈),供 inline 脚本零依赖地
diff --git a/src/lib/floating-ball-gestures.test.ts b/src/lib/floating-ball-gestures.test.ts
index 3b0f5345bc..449326301a 100644
--- a/src/lib/floating-ball-gestures.test.ts
+++ b/src/lib/floating-ball-gestures.test.ts
@@ -40,8 +40,7 @@ function run(points: [number, number][]): FloatingBallGesture | null {
const tracker = createFloatingBallTracker()
tracker.start(points[0][0], points[0][1])
for (const point of points.slice(1)) tracker.move(point[0], point[1])
- const last = points[points.length - 1]
- return tracker.end(last[0], last[1])
+ return tracker.end()
}
const S = SWIPE_PX
@@ -144,7 +143,7 @@ describe("two-stage trails", () => {
expect(trail([0, -50], [60, -50])).toBe("upThenRight")
expect(trail([-40, -40], [-40, 40])).toBe("upLeftThenDown")
expect(trail([40, -40], [40, 40])).toBe("upRightThenDown")
- expect(trail([0, -50], [(S + 10), (S + 10)])).toBe("upThenDownRight")
+ expect(trail([0, -50], [S + 10, S + 10])).toBe("upThenDownRight")
})
it("folds the batch-v82 downward and horizontal starts", () => {
@@ -155,9 +154,7 @@ describe("two-stage trails", () => {
expect(trail([50, 0], [50, S + 20])).toBe("rightThenDown")
expect(trail([0, 50], [S + 20, 50])).toBe("downThenRight")
expect(trail([0, 50], [-(S + 20), 50])).toBe("downThenLeft")
- expect(trail([S + 10, S + 10], [S + 10, -(S + 20)])).toBe(
- "downRightThenUp"
- )
+ expect(trail([S + 10, S + 10], [S + 10, -(S + 20)])).toBe("downRightThenUp")
expect(trail([-(S + 10), S + 10], [-(S + 10), -(S + 20)])).toBe(
"downLeftThenUp"
)
diff --git a/src/lib/floating-ball-gestures.ts b/src/lib/floating-ball-gestures.ts
index 6e58f98522..30da2f4ac7 100644
--- a/src/lib/floating-ball-gestures.ts
+++ b/src/lib/floating-ball-gestures.ts
@@ -257,13 +257,28 @@ function singleStage(stage: Segment): FloatingBallGesture | null {
}
}
+/**
+ * Name the gesture the trail would commit right now, loose-matched — the hint
+ * pill's source of truth. Mirrors the tracker's own folding, so the pill and
+ * the commit can never disagree. An unfinished two-stage trail falls back to
+ * its last stage so the pill shows what a stop right there would fire.
+ */
+export function previewGesture(
+ trail: readonly Segment[]
+): FloatingBallGesture | null {
+ if (trail.length === 0) return null
+ const folded = foldTrail(trail)
+ if (folded) return folded
+ return singleStage(trail[trail.length - 1])
+}
+
export interface FloatingBallTracker {
/** Touchdown. */
start(x: number, y: number): void
/** Every pointer sample while the press is down. */
move(x: number, y: number): void
/** Lift-off: the path gesture, or null when this press was not one. */
- end(x: number, y: number): FloatingBallGesture | null
+ end(): FloatingBallGesture | null
/** Whether the press has travelled far enough to be a gesture at all. */
readonly moved: boolean
/** Stages recognised so far, oldest first. Exposed for tests and debugging. */
@@ -329,7 +344,7 @@ export function createFloatingBallTracker(): FloatingBallTracker {
anchorX = x
anchorY = y
},
- end(x, y) {
+ end(): FloatingBallGesture | null {
if (!moved) return null
// A completed trail is judged on its stages, not on how far the finger
// ended from the origin: round trips (↓↑, ↑↓) naturally land back where
From f82b86a835f15a6abd4d39dc9469f921c9b3019a Mon Sep 17 00:00:00 2001
From: fengx
Date: Sun, 18 Oct 2026 00:44:36 +0800
Subject: [PATCH 07/18] =?UTF-8?q?feat(floating-ball):=20batch=20v82=20P3?=
=?UTF-8?q?=20=E2=80=94=20wire=2010=20new=20actions=20with=20guards=20and?=
=?UTF-8?q?=20feedback?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- openTodos/openTodosNew/openAutomations/openCanvas route the workbench;
openTodosNew parks a task draft so the composer opens on an already-active
tasks route too
- openAgents/openSystemAdmin open the settings window at the section
- renameConversation dispatches a global event carrying the DB id; the
conversation header whose id matches opens its rename dialog (multi-tab
safe); drafts get a toast instead
- openSessionFolder opens the aux file tree, guarded on an active folder
- cycleAgent cycles enabled+available agents on the active draft tab via
confirmDraftAgent; on a saved conversation it opens a fresh draft pinned
(forceAgent) to the next agent; cycleFavoriteAgent restricts the cycle to
the user's favorite list from floating-ball settings
- FloatingBall.toasts i18n keys across all 12 locale files
---
.../conversation-detail-header.tsx | 19 +-
.../workspace-chrome-controller.test.tsx | 166 +++++++++++++++++-
.../layout/workspace-chrome-controller.tsx | 119 ++++++++++++-
src/i18n/messages/ar.json | 7 +-
src/i18n/messages/de.json | 7 +-
src/i18n/messages/en.json | 7 +-
src/i18n/messages/es.json | 7 +-
src/i18n/messages/fr.json | 7 +-
src/i18n/messages/ja.json | 7 +-
src/i18n/messages/ko.json | 7 +-
src/i18n/messages/pt.json | 7 +-
src/i18n/messages/zh-CN.json | 7 +-
src/i18n/messages/zh-TW.json | 7 +-
src/lib/rename-conversation-events.ts | 17 ++
14 files changed, 370 insertions(+), 21 deletions(-)
create mode 100644 src/lib/rename-conversation-events.ts
diff --git a/src/components/conversations/conversation-detail-header.tsx b/src/components/conversations/conversation-detail-header.tsx
index a24c3bc7a4..4f1c8717d1 100644
--- a/src/components/conversations/conversation-detail-header.tsx
+++ b/src/components/conversations/conversation-detail-header.tsx
@@ -1,6 +1,6 @@
"use client"
-import { memo, useCallback, useState } from "react"
+import { memo, useCallback, useEffect, useState } from "react"
import {
ChevronRight,
Circle,
@@ -21,6 +21,7 @@ import {
updateConversationTitle,
} from "@/lib/api"
import { formatConversationTitle } from "@/lib/conversation-title"
+import { RENAME_CONVERSATION_EVENT } from "@/lib/rename-conversation-events"
import { ConversationHeaderFolderPicker } from "@/components/chat/conversation-context-bar"
import { useAppWorkspaceStore } from "@/stores/app-workspace-store"
import { useTabActions } from "@/contexts/tab-context"
@@ -211,6 +212,22 @@ export const ConversationDetailHeader = memo(function ConversationDetailHeader({
setRenameTarget(null)
}, [renameTarget, renameValue, refreshConversations])
+ // Floating-ball "rename session": the event carries the DB id and every
+ // mounted header instance hears it — only the one whose conversation matches
+ // opens its dialog (multi-tab safe). Drafts (id null) have nothing to rename.
+ useEffect(() => {
+ if (conversationId == null) return
+ const onRename = (e: Event) => {
+ const id = (e as CustomEvent<{ conversationId: number }>).detail
+ ?.conversationId
+ if (id !== conversationId || renameTarget != null) return
+ setRenameValue(title || "")
+ setRenameTarget({ id: conversationId, title })
+ }
+ window.addEventListener(RENAME_CONVERSATION_EVENT, onRename)
+ return () => window.removeEventListener(RENAME_CONVERSATION_EVENT, onRename)
+ }, [conversationId, renameTarget, title])
+
const handleStatusChange = useCallback(
(next: ConversationStatus) => {
if (conversationId == null) return
diff --git a/src/components/layout/workspace-chrome-controller.test.tsx b/src/components/layout/workspace-chrome-controller.test.tsx
index 5b1a377fb2..6c7f70294a 100644
--- a/src/components/layout/workspace-chrome-controller.test.tsx
+++ b/src/components/layout/workspace-chrome-controller.test.tsx
@@ -25,6 +25,15 @@ const state = vi.hoisted(() => ({
desktop: true,
shortcuts: {} as Record,
listeners: new Map void>(),
+ // Floating-ball action context: the active tab row and the agent universe.
+ activeTab: null as {
+ id: string
+ conversationId: number | null
+ agentType: string
+ } | null,
+ sortedAgentTypes: ["zcode", "codex"] as string[],
+ favoriteAgents: [] as string[],
+ activeFolder: { id: 1, path: "/repo" } as { id: number; path: string } | null,
}))
const spies = vi.hoisted(() => ({
@@ -36,9 +45,21 @@ const spies = vi.hoisted(() => ({
setActivePane: vi.fn(),
closeCurrentWindow: vi.fn(() => Promise.resolve()),
subscribe: vi.fn(),
+ setRoute: vi.fn(),
+ openSettingsWindow: vi.fn(() => Promise.resolve()),
+ auxOpenTab: vi.fn(),
+ confirmDraftAgent: vi.fn(),
+ openChatModeTab: vi.fn(),
+ openNewConversationTab: vi.fn(),
}))
-vi.mock("@/lib/api", () => ({ openSettingsWindow: vi.fn() }))
+/** Captured from the (stubbed) FloatingBall: the controller's action handler. */
+let ballAction: ((action: string) => void) | null = null
+
+vi.mock("@/lib/api", () => ({ openSettingsWindow: spies.openSettingsWindow }))
+vi.mock("next-intl", () => ({
+ useTranslations: () => (key: string) => key,
+}))
// The floating ball reads the active ACP connection (to stop a turn) and the
// zoom level. Both pull provider modules this test does not exercise, and the
// ACP context imports the workspace store in a shape the stub below does not
@@ -50,12 +71,25 @@ vi.mock("@/contexts/acp-connections-context", () => ({
}))
vi.mock("@/hooks/use-appearance", () => ({
useZoomLevel: () => ({ zoomLevel: 100, setZoomLevel: vi.fn() }),
+ useFloatingBall: () => ({
+ floatingBallFavoriteAgents: state.favoriteAgents,
+ }),
+}))
+vi.mock("@/hooks/use-sorted-available-agents", () => ({
+ useSortedAvailableAgents: () => ({
+ sortedTypes: state.sortedAgentTypes,
+ fresh: true,
+ refresh: () => Promise.resolve(),
+ }),
}))
vi.mock("@/components/layout/floating-ball", () => ({
- FloatingBall: () => null,
+ FloatingBall: ({ onAction }: { onAction: (action: string) => void }) => {
+ ballAction = onAction
+ return null
+ },
}))
vi.mock("@/contexts/active-folder-context", () => ({
- useActiveFolder: () => ({ activeFolder: { id: 1, path: "/repo" } }),
+ useActiveFolder: () => ({ activeFolder: state.activeFolder }),
}))
vi.mock("@/hooks/use-is-active-chat-mode", () => ({
useIsActiveChatMode: () => false,
@@ -64,23 +98,32 @@ vi.mock("@/contexts/sidebar-context", () => ({
useSidebarContext: () => ({ toggle: vi.fn() }),
}))
vi.mock("@/contexts/aux-panel-context", () => ({
- useAuxPanelContext: () => ({ toggle: vi.fn() }),
+ useAuxPanelContext: () => ({ toggle: vi.fn(), openTab: spies.auxOpenTab }),
}))
vi.mock("@/contexts/terminal-context", () => ({
useTerminalContext: () => ({ toggle: vi.fn() }),
}))
vi.mock("@/contexts/tab-context", () => ({
useTabActions: () => ({
- openNewConversationTab: vi.fn(),
+ openNewConversationTab: spies.openNewConversationTab,
openTab: vi.fn(),
switchTab: spies.switchTab,
closeTab: spies.closeTab,
+ confirmDraftAgent: spies.confirmDraftAgent,
+ openChatModeTab: spies.openChatModeTab,
}),
useTabStore: (
- selector: (s: { tabs: { id: string }[]; activeTabId: string | null }) => T
+ selector: (s: {
+ tabs: { id: string; conversationId: number | null; agentType: string }[]
+ activeTabId: string | null
+ }) => T
) =>
selector({
- tabs: state.activeTabId ? [{ id: state.activeTabId }] : [],
+ tabs: state.activeTabId
+ ? state.activeTab
+ ? [state.activeTab]
+ : [{ id: state.activeTabId, conversationId: 7, agentType: "zcode" }]
+ : [],
activeTabId: state.activeTabId,
}),
}))
@@ -105,7 +148,10 @@ vi.mock("@/contexts/workspace-context", () => ({
}),
}))
vi.mock("@/contexts/workbench-route-context", () => ({
- useWorkbenchRoute: () => ({ openConversations: vi.fn() }),
+ useWorkbenchRoute: () => ({
+ openConversations: vi.fn(),
+ setRoute: spies.setRoute,
+ }),
}))
vi.mock("@/contexts/search-dialog-context", () => ({
useSearchDialog: () => ({ open: false, setOpen: vi.fn() }),
@@ -182,6 +228,16 @@ beforeEach(() => {
return () => state.listeners.delete(event)
}
)
+ spies.setRoute.mockClear()
+ spies.openSettingsWindow.mockClear()
+ spies.auxOpenTab.mockClear()
+ spies.confirmDraftAgent.mockClear()
+ spies.openChatModeTab.mockClear()
+ spies.openNewConversationTab.mockClear()
+ state.activeTab = { id: "conv-1", conversationId: 7, agentType: "zcode" }
+ state.sortedAgentTypes = ["zcode", "codex"]
+ state.favoriteAgents = []
+ state.activeFolder = { id: 1, path: "/repo" }
})
afterEach(() => {
@@ -381,3 +437,97 @@ describe("WorkspaceChromeController — ⌘W the page hears", () => {
expect(event.defaultPrevented).toBe(false)
})
})
+
+describe("WorkspaceChromeController — floating-ball actions", () => {
+ function fire(action: string): void {
+ render()
+ expect(typeof ballAction).toBe("function")
+ ballAction?.(action)
+ }
+
+ it("routes the workspace actions", async () => {
+ fire("openTodos")
+ expect(spies.setRoute).toHaveBeenCalledWith("tasks")
+ fire("openAutomations")
+ expect(spies.setRoute).toHaveBeenCalledWith("automations")
+ fire("openCanvas")
+ expect(spies.setRoute).toHaveBeenCalledWith("canvas")
+ fire("openAgents")
+ await waitFor(() =>
+ expect(spies.openSettingsWindow).toHaveBeenCalledWith("agents")
+ )
+ fire("openSystemAdmin")
+ await waitFor(() =>
+ expect(spies.openSettingsWindow).toHaveBeenCalledWith("system")
+ )
+ })
+
+ it("opens the new-to-do composer even when the tasks route is already active", () => {
+ const received: CustomEvent[] = []
+ const listener = (e: Event) => received.push(e as CustomEvent)
+ window.addEventListener("codeg:create-task-from-text", listener)
+ fire("openTodosNew")
+ window.removeEventListener("codeg:create-task-from-text", listener)
+ expect(spies.setRoute).toHaveBeenCalledWith("tasks")
+ expect(received).toHaveLength(1)
+ })
+
+ it("renames the active tab's conversation by id", () => {
+ const received: unknown[] = []
+ const listener = (e: Event) => received.push((e as CustomEvent).detail)
+ window.addEventListener("codeg:rename-conversation", listener)
+ fire("renameConversation")
+ window.removeEventListener("codeg:rename-conversation", listener)
+ expect(received).toEqual([{ conversationId: 7 }])
+ })
+
+ it("opens the file tree only with a workspace folder", () => {
+ fire("openSessionFolder")
+ expect(spies.auxOpenTab).toHaveBeenCalledWith("file_tree")
+
+ state.activeFolder = null
+ fire("openSessionFolder")
+ expect(spies.auxOpenTab).toHaveBeenCalledTimes(1)
+ })
+
+ it("cycles the active draft tab's agent and confirms it", () => {
+ state.activeTab = {
+ id: "conv-1",
+ conversationId: null,
+ agentType: "zcode",
+ }
+ fire("cycleAgent")
+ expect(spies.confirmDraftAgent).toHaveBeenCalledWith("conv-1", "codex")
+ // The store would have applied the switch; reflect it like the real tab
+ // row would, so the next stroke continues from codex.
+ state.activeTab = {
+ id: "conv-1",
+ conversationId: null,
+ agentType: "codex",
+ }
+ fire("cycleAgent")
+ expect(spies.confirmDraftAgent).toHaveBeenLastCalledWith("conv-1", "zcode")
+ })
+
+ it("pins a new draft to the next agent when the active tab is saved", () => {
+ fire("cycleAgent")
+ expect(spies.confirmDraftAgent).not.toHaveBeenCalled()
+ expect(spies.openNewConversationTab).toHaveBeenCalledWith(
+ 1,
+ "/repo",
+ expect.objectContaining({ forceAgent: "codex" })
+ )
+ })
+
+ it("cycles only within the favorite list for cycleFavoriteAgent", () => {
+ state.sortedAgentTypes = ["zcode", "codex", "cline"]
+ state.favoriteAgents = ["codex", "cline"]
+ fire("cycleFavoriteAgent")
+ // Current tab agent zcode is not in the list → head of the list.
+ expect(spies.openNewConversationTab).toHaveBeenCalledWith(
+ 1,
+ "/repo",
+ expect.objectContaining({ forceAgent: "codex" })
+ )
+ })
+})
diff --git a/src/components/layout/workspace-chrome-controller.tsx b/src/components/layout/workspace-chrome-controller.tsx
index 3155eea62c..54a290df78 100644
--- a/src/components/layout/workspace-chrome-controller.tsx
+++ b/src/components/layout/workspace-chrome-controller.tsx
@@ -6,13 +6,16 @@ import {
useAcpActions,
useConnectionStore,
} from "@/contexts/acp-connections-context"
-import { useZoomLevel } from "@/hooks/use-appearance"
+import { useZoomLevel, useFloatingBall } from "@/hooks/use-appearance"
import { useActiveFolder } from "@/contexts/active-folder-context"
import { useIsActiveChatMode } from "@/hooks/use-is-active-chat-mode"
import { useSidebarContext } from "@/contexts/sidebar-context"
import { useAuxPanelContext } from "@/contexts/aux-panel-context"
import { useTerminalContext } from "@/contexts/terminal-context"
+import { useSortedAvailableAgents } from "@/hooks/use-sorted-available-agents"
import { useTabActions, useTabStore } from "@/contexts/tab-context"
+import { requestCreateTaskFromText } from "@/lib/task-compose-events"
+import { requestRenameConversation } from "@/lib/rename-conversation-events"
import {
useWorkspaceActions,
useWorkspaceFileTabs,
@@ -47,8 +50,28 @@ import { SearchCommandDialog } from "@/components/conversations/search-command-d
import { FloatingBall } from "@/components/layout/floating-ball"
import { WorkspaceFolderDialog } from "@/components/layout/workspace-folder-dialog"
import { stepZoom, DEFAULT_ZOOM_LEVEL } from "@/lib/theme-presets"
+import { toast } from "sonner"
+import { useTranslations } from "next-intl"
+import type { AgentType } from "@/lib/types"
import type { FloatingBallAction } from "@/lib/floating-ball-gestures"
+/**
+ * Next entry in a cycling list. With a current agent it picks the following
+ * one (wrapping); without one — or when the current agent has since dropped
+ * out of the list — it starts from the head. The favorites list re-reads its
+ * configured order on every stroke, so cycling there follows what settings
+ * shows rather than a stale snapshot.
+ */
+function nextInCycle(
+ current: AgentType | undefined,
+ list: AgentType[]
+): AgentType {
+ if (list.length === 0) return current ?? list[0]
+ if (current == null || !list.includes(current)) return list[0]
+ const index = list.indexOf(current)
+ return list[(index + 1) % list.length]
+}
+
/**
* Headless owner of the workspace's global keyboard shortcuts and the two
* dialogs the shortcuts summon (search, remote directory browser). These used
@@ -58,6 +81,7 @@ import type { FloatingBallAction } from "@/lib/floating-ball-gestures"
* visible bar. Renders no visible chrome — only the dialogs.
*/
export function WorkspaceChromeController() {
+ const tBall = useTranslations("FloatingBall")
const { activeFolder } = useActiveFolder()
const isChatMode = useIsActiveChatMode()
const { toggle } = useSidebarContext()
@@ -81,7 +105,7 @@ export function WorkspaceChromeController() {
openBrowserTab,
setActivePane,
} = useWorkspaceActions()
- const { openConversations } = useWorkbenchRoute()
+ const { openConversations, setRoute } = useWorkbenchRoute()
const { shortcuts } = useShortcutSettings()
const { zoomLevel, setZoomLevel } = useZoomLevel()
// Stopping a turn is the one floating-ball action with no shortcut: the
@@ -90,6 +114,16 @@ export function WorkspaceChromeController() {
// what the workspace considers "the turn in front of the user".
const { cancel } = useAcpActions()
const { getActiveKey } = useConnectionStore()
+ // Agent cycling (floating ball "next agent" / "favorite agents") needs the
+ // same enabled+available list the draft tabs resolve their defaults from.
+ const { sortedTypes: sortedAvailableAgents } = useSortedAvailableAgents()
+ const { confirmDraftAgent, openChatModeTab } = useTabActions()
+ // Session files ("open the session folder") opens the aux panel's file tree;
+ // no active folder means there is nothing to reveal (same guard as the
+ // toggle-files keyboard shortcut below).
+ const auxPanel = useAuxPanelContext()
+ const activeTab = tabs.find((tab) => tab.id === activeTabId)
+ const { floatingBallFavoriteAgents: favoriteAgents } = useFloatingBall()
// Search open-state is shared (see search-dialog-context): the trigger lives
// in the sidebar, but this always-mounted controller owns the dialog and the
// ⌘K shortcut so search works even when the sidebar is collapsed.
@@ -499,23 +533,104 @@ export function WorkspaceChromeController() {
case "openSettings":
handleOpenSettings()
return
+ case "openTodos":
+ setRoute("tasks")
+ return
+ case "openTodosNew":
+ // Park the draft before switching — the Tasks page consumes it on
+ // mount, and on the live event when the route is already active.
+ requestCreateTaskFromText({
+ text: "",
+ folderId: activeFolder?.id ?? null,
+ })
+ setRoute("tasks")
+ return
+ case "openAutomations":
+ setRoute("automations")
+ return
+ case "openCanvas":
+ setRoute("canvas")
+ return
+ case "openAgents":
+ void openSettingsWindow("agents").catch((err) => {
+ console.error("[WorkspaceChromeController] agents settings:", err)
+ })
+ return
+ case "openSystemAdmin":
+ void openSettingsWindow("system").catch((err) => {
+ console.error("[WorkspaceChromeController] system settings:", err)
+ })
+ return
+ case "renameConversation": {
+ const id = activeTab?.conversationId
+ if (id == null) {
+ toast.info(tBall("toasts.renameNeedsSavedSession"))
+ return
+ }
+ requestRenameConversation({ conversationId: id })
+ return
+ }
+ case "openSessionFolder":
+ if (!activeFolder) {
+ toast.info(tBall("toasts.sessionFolderNeedsWorkspace"))
+ return
+ }
+ auxPanel.openTab("file_tree")
+ return
+ case "cycleAgent":
+ case "cycleFavoriteAgent": {
+ const list =
+ action === "cycleAgent"
+ ? sortedAvailableAgents
+ : sortedAvailableAgents.filter((a) => favoriteAgents.includes(a))
+ if (list.length <= 1) {
+ toast.info(tBall("toasts.cycleNeedsMoreAgents"))
+ return
+ }
+ const tab = activeTab
+ // The switch retargets the draft's ACP connection via
+ // useConnectionLifecycle; a persisted conversation's agent is fixed,
+ // so open a fresh draft pinned to the next agent instead.
+ if (!tab || tab.conversationId != null) {
+ const next = nextInCycle(tab?.agentType, list)
+ if (activeFolder) {
+ openNewConversationTab(activeFolder.id, activeFolder.path, {
+ forceAgent: next,
+ })
+ } else {
+ openChatModeTab({ forceAgent: next })
+ }
+ return
+ }
+ const next = nextInCycle(tab.agentType, list)
+ confirmDraftAgent(tab.id, next)
+ return
+ }
case "panel":
return
}
},
[
activeFolder,
+ activeTab,
activeTabId,
+ auxPanel,
cancel,
+ confirmDraftAgent,
+ favoriteAgents,
getActiveKey,
handleOpenFolder,
handleOpenSettings,
+ openChatModeTab,
openConversations,
openNewConversationTab,
reopenClosedTab,
setSearchOpen,
+ setRoute,
setZoomLevel,
+ sortedAvailableAgents,
switchTab,
+ tBall,
tabs,
toggle,
toggleTerminal,
diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json
index bb16902416..bf854b2c0e 100644
--- a/src/i18n/messages/ar.json
+++ b/src/i18n/messages/ar.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "أعلى-يسار ثم يمين",
"upRightThenLeft": "أعلى-يمين ثم يسار"
},
- "favoriteAgentsEmpty": "لا يوجد وكلاء متاحون"
+ "favoriteAgentsEmpty": "لا يوجد وكلاء متاحون",
+ "toasts": {
+ "renameNeedsSavedSession": "إعادة التسمية تعمل على الجلسات المحفوظة فقط — أرسل رسالة أولاً.",
+ "sessionFolderNeedsWorkspace": "افتح مجلد مساحة العمل أولاً.",
+ "cycleNeedsMoreAgents": "وكيل واحد متاح فقط — لا يوجد ما يمكن التبديل إليه."
+ }
}
}
diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json
index f1e38eb844..f9c30e597f 100644
--- a/src/i18n/messages/de.json
+++ b/src/i18n/messages/de.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "Oben-li., dann rechts",
"upRightThenLeft": "Oben-re., dann links"
},
- "favoriteAgentsEmpty": "Keine Agenten verfügbar"
+ "favoriteAgentsEmpty": "Keine Agenten verfügbar",
+ "toasts": {
+ "renameNeedsSavedSession": "Umbenennen gilt nur für gespeicherte Sitzungen – senden Sie zuerst eine Nachricht.",
+ "sessionFolderNeedsWorkspace": "Öffnen Sie zuerst einen Arbeitsbereich-Ordner.",
+ "cycleNeedsMoreAgents": "Nur ein Agent verfügbar – nichts zum Wechseln."
+ }
}
}
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 4d9f43bf03..631faac6cf 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "Up-left, then right",
"upRightThenLeft": "Up-right, then left"
},
- "favoriteAgentsEmpty": "No available agents"
+ "favoriteAgentsEmpty": "No available agents",
+ "toasts": {
+ "renameNeedsSavedSession": "Rename works on a saved session — send a message first.",
+ "sessionFolderNeedsWorkspace": "Open a workspace folder first.",
+ "cycleNeedsMoreAgents": "Only one agent available — nothing to cycle."
+ }
}
}
diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json
index 1a7fdba587..0734ca1a46 100644
--- a/src/i18n/messages/es.json
+++ b/src/i18n/messages/es.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "Arriba-izq., luego derecha",
"upRightThenLeft": "Arriba-der., luego izquierda"
},
- "favoriteAgentsEmpty": "No hay agentes disponibles"
+ "favoriteAgentsEmpty": "No hay agentes disponibles",
+ "toasts": {
+ "renameNeedsSavedSession": "Renombrar solo funciona en sesiones guardadas: envía un mensaje primero.",
+ "sessionFolderNeedsWorkspace": "Abre antes una carpeta de espacio de trabajo.",
+ "cycleNeedsMoreAgents": "Solo hay un agente disponible: nada que alternar."
+ }
}
}
diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json
index cfa49392eb..da1c5539bc 100644
--- a/src/i18n/messages/fr.json
+++ b/src/i18n/messages/fr.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "Haut-g., puis droite",
"upRightThenLeft": "Haut-dr., puis gauche"
},
- "favoriteAgentsEmpty": "Aucun agent disponible"
+ "favoriteAgentsEmpty": "Aucun agent disponible",
+ "toasts": {
+ "renameNeedsSavedSession": "Renommer ne s'applique qu'aux sessions enregistrées — envoyez d'abord un message.",
+ "sessionFolderNeedsWorkspace": "Ouvrez d'abord un dossier d'espace de travail.",
+ "cycleNeedsMoreAgents": "Un seul agent disponible — rien à parcourir."
+ }
}
}
diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json
index 25964435b8..c00a6584c7 100644
--- a/src/i18n/messages/ja.json
+++ b/src/i18n/messages/ja.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "左上から右",
"upRightThenLeft": "右上から左"
},
- "favoriteAgentsEmpty": "利用可能なエージェントがありません"
+ "favoriteAgentsEmpty": "利用可能なエージェントがありません",
+ "toasts": {
+ "renameNeedsSavedSession": "名前の変更は保存済みセッションのみ有効です。まずメッセージを送信してください。",
+ "sessionFolderNeedsWorkspace": "先にワークスペースフォルダを開いてください。",
+ "cycleNeedsMoreAgents": "利用可能なエージェントが1つだけのため、切り替えできません。"
+ }
}
}
diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json
index a430f35e7a..8e375dbd77 100644
--- a/src/i18n/messages/ko.json
+++ b/src/i18n/messages/ko.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "왼위→오른",
"upRightThenLeft": "오른위→왼"
},
- "favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다"
+ "favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다",
+ "toasts": {
+ "renameNeedsSavedSession": "이름 바꾸기는 저장된 세션에만 적용됩니다. 먼저 메시지를 보내세요.",
+ "sessionFolderNeedsWorkspace": "먼저 작업 공간 폴더를 여세요.",
+ "cycleNeedsMoreAgents": "사용 가능한 에이전트가 하나뿐이어서 전환할 수 없습니다."
+ }
}
}
diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json
index 01de443c45..acc64d9b91 100644
--- a/src/i18n/messages/pt.json
+++ b/src/i18n/messages/pt.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "Cima-esq., depois direita",
"upRightThenLeft": "Cima-dir., depois esquerda"
},
- "favoriteAgentsEmpty": "Nenhum agente disponível"
+ "favoriteAgentsEmpty": "Nenhum agente disponível",
+ "toasts": {
+ "renameNeedsSavedSession": "Renomear só funciona em sessões salvas — envie uma mensagem primeiro.",
+ "sessionFolderNeedsWorkspace": "Abra antes uma pasta de espaço de trabalho.",
+ "cycleNeedsMoreAgents": "Só há um agente disponível — nada para alternar."
+ }
}
}
diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json
index 9e2d16d906..45f4b49a8a 100644
--- a/src/i18n/messages/zh-CN.json
+++ b/src/i18n/messages/zh-CN.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "左上再右",
"upRightThenLeft": "右上再左"
},
- "favoriteAgentsEmpty": "暂无可用智能体"
+ "favoriteAgentsEmpty": "暂无可用智能体",
+ "toasts": {
+ "renameNeedsSavedSession": "重命名只对已保存的会话生效——先发一条消息。",
+ "sessionFolderNeedsWorkspace": "请先打开一个工作区文件夹。",
+ "cycleNeedsMoreAgents": "可用智能体只有一个,无可切换。"
+ }
}
}
diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json
index bc88edf1ff..bdcb6dfb2d 100644
--- a/src/i18n/messages/zh-TW.json
+++ b/src/i18n/messages/zh-TW.json
@@ -7466,6 +7466,11 @@
"upLeftThenRight": "左上再右",
"upRightThenLeft": "右上再左"
},
- "favoriteAgentsEmpty": "暫無可用代理人"
+ "favoriteAgentsEmpty": "暫無可用代理人",
+ "toasts": {
+ "renameNeedsSavedSession": "重新命名只對已儲存的會話生效——先發一則訊息。",
+ "sessionFolderNeedsWorkspace": "請先開啟一個工作區資料夾。",
+ "cycleNeedsMoreAgents": "可用智慧型代理只有一個,無可切換。"
+ }
}
}
diff --git a/src/lib/rename-conversation-events.ts b/src/lib/rename-conversation-events.ts
new file mode 100644
index 0000000000..e9956e9a8a
--- /dev/null
+++ b/src/lib/rename-conversation-events.ts
@@ -0,0 +1,17 @@
+/**
+ * "Rename the current session" hand-off from the floating ball. The header
+ * that owns the rename dialog is mounted per conversation tab, so the signal
+ * carries the DB id and each instance compares it against its own — a tab
+ * whose conversation does not match ignores the event (multi-tab safe, same
+ * idiom as task-compose-events but synchronous: the header stays mounted).
+ */
+
+export const RENAME_CONVERSATION_EVENT = "codeg:rename-conversation"
+
+export interface RenameConversationDetail {
+ conversationId: number
+}
+
+export function requestRenameConversation(detail: RenameConversationDetail) {
+ window.dispatchEvent(new CustomEvent(RENAME_CONVERSATION_EVENT, { detail }))
+}
From d5224325ac5aba12d5271a616e156535d7562e32 Mon Sep 17 00:00:00 2001
From: fengx
Date: Sun, 18 Oct 2026 04:14:17 +0800
Subject: [PATCH 08/18] feat(floating-ball): settings labels i18n + 9 new
bindable actions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Settings screen gesture/action labels now read the translated
FloatingBall namespace (arrows: ↑↓←→, compound '↑ then ←'), instead of
the untranslated AppearanceSettings English mirror
- New actions: openBallBindings, cycleRunningSessions (0/1/2+ running
semantics via ACP connection status), cycleRecentSessions (LRU queue
+ depth setting 2-4), deleteCurrentConversation (reuses header
confirm dialog), openImportSessions, togglePinConversation,
focusModeSelector (signal prop chain to MessageInput),
togglePlanFullAccess (plan substring + matchFullAccessMode),
openCollaboration; new actions ship unbound by default
- New modules: recent-sessions-prefs (localStorage LRU, capacity 8,
corrupted-storage tolerant), floating-ball-session-events
(conversationId-filtered CustomEvents, null-matches-null)
- tab-store: remember recent conversation on focusTab/bindConversationTab
- 10 locales updated (parity test enforced); 2 new unit test files
---
src/components/chat/chat-input.tsx | 4 +
src/components/chat/conversation-shell.tsx | 4 +
src/components/chat/message-input.tsx | 15 +
src/components/chat/mode-selector.tsx | 71 +++++
.../conversation-detail-header.tsx | 19 ++
.../conversation-detail-panel.tsx | 66 +++++
.../workspace-chrome-controller.test.tsx | 19 +-
.../layout/workspace-chrome-controller.tsx | 111 +++++++-
.../settings/appearance-settings.tsx | 68 ++++-
src/i18n/messages/ar.json | 264 ++++++++----------
src/i18n/messages/de.json | 264 ++++++++----------
src/i18n/messages/en.json | 212 +++++++-------
src/i18n/messages/es.json | 264 ++++++++----------
src/i18n/messages/fr.json | 262 ++++++++---------
src/i18n/messages/ja.json | 262 ++++++++---------
src/i18n/messages/ko.json | 264 ++++++++----------
src/i18n/messages/pt.json | 262 ++++++++---------
src/i18n/messages/zh-CN.json | 262 ++++++++---------
src/i18n/messages/zh-TW.json | 262 ++++++++---------
src/lib/floating-ball-gestures.ts | 9 +
src/lib/floating-ball-session-events.test.ts | 52 ++++
src/lib/floating-ball-session-events.ts | 47 ++++
src/lib/recent-sessions-prefs.test.ts | 77 +++++
src/lib/recent-sessions-prefs.ts | 92 ++++++
src/stores/tab-store.ts | 13 +
25 files changed, 1841 insertions(+), 1404 deletions(-)
create mode 100644 src/components/chat/mode-selector.tsx
create mode 100644 src/lib/floating-ball-session-events.test.ts
create mode 100644 src/lib/floating-ball-session-events.ts
create mode 100644 src/lib/recent-sessions-prefs.test.ts
create mode 100644 src/lib/recent-sessions-prefs.ts
diff --git a/src/components/chat/chat-input.tsx b/src/components/chat/chat-input.tsx
index 4458a603a3..760b3fbcb0 100644
--- a/src/components/chat/chat-input.tsx
+++ b/src/components/chat/chat-input.tsx
@@ -28,6 +28,8 @@ interface ChatInputProps {
agentName?: string
onFocus?: () => void
onSend: (draft: PromptDraft, modeId?: string | null) => void
+ /** Pass-through: see `MessageInput.modeSelectorSignal`. */
+ modeSelectorSignal?: number
onCancel: () => void
modes?: SessionModeInfo[]
configOptions?: SessionConfigOptionInfo[]
@@ -109,6 +111,7 @@ export const ChatInput = memo(function ChatInput({
agentName,
onFocus,
onSend,
+ modeSelectorSignal,
onCancel,
modes,
configOptions,
@@ -205,6 +208,7 @@ export const ChatInput = memo(function ChatInput({
)}
void
+ /** Pass-through: see `MessageInput.modeSelectorSignal`. */
+ modeSelectorSignal?: number
onConfigOptionChange?: (configId: string, valueId: string) => void
agentType?: AgentType | null
availableCommands?: AvailableCommandInfo[] | null
@@ -198,6 +200,7 @@ export function ConversationShell({
selectorsLoading = false,
selectedModeId,
onModeChange,
+ modeSelectorSignal,
onConfigOptionChange,
agentType,
availableCommands,
@@ -310,6 +313,7 @@ export function ConversationShell({
{!hideInput && (
void
+ /** Bumped by the host (floating ball "mode selector" action) to open the
+ * inline mode dropdown; the effect below re-fires on every increment. */
+ modeSelectorSignal?: number
placeholder?: string
defaultPath?: string
disabled?: boolean
@@ -311,6 +314,7 @@ function SelectorLoadingChip({ label }: { label: string }) {
export function MessageInput({
onSend,
+ modeSelectorSignal: modeSelectorSignalProp = 0,
placeholder,
defaultPath,
disabled = false,
@@ -907,6 +911,17 @@ export function MessageInput({
// Antigravity after its commands on `/`.
const [slashMenuOpen, setSlashMenuOpen] = useState(false)
const [slashSelectedIndex, setSlashSelectedIndex] = useState(0)
+ // One-shot signal from the floating ball's "mode selector" action: the
+ // imperative openModeSelector handle bumps a counter; the effect below
+ // re-opens the dropdown when it advances. Programmatic trigger clicks are
+ // idempotent while the menu is already open.
+ useEffect(() => {
+ if (modeSelectorSignalProp === 0) return
+ const trigger = containerRef.current?.querySelector(
+ "[data-mode-selector-trigger]"
+ )
+ trigger?.click()
+ }, [modeSelectorSignalProp])
// The trigger char (`/` for agent commands, `$` for Codex skills) and the
// typed filter token, both derived from the editor caret by
// `detectSlashTrigger` rather than from a raw string offset.
diff --git a/src/components/chat/mode-selector.tsx b/src/components/chat/mode-selector.tsx
new file mode 100644
index 0000000000..94019be7ec
--- /dev/null
+++ b/src/components/chat/mode-selector.tsx
@@ -0,0 +1,71 @@
+"use client"
+
+import { ChevronDown } from "lucide-react"
+import { Button } from "@/components/ui/button"
+import {
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuRadioGroup,
+ DropdownMenuRadioItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu"
+import { DropdownRadioItemContent } from "@/components/chat/dropdown-radio-item-content"
+import { SelectorTooltip } from "@/components/chat/selector-tooltip"
+import type { SessionModeInfo } from "@/lib/types"
+
+interface ModeSelectorProps {
+ modes: SessionModeInfo[]
+ selectedModeId: string | null
+ onSelect: (modeId: string) => void
+ label: string
+}
+
+export function InlineModeSelector({
+ modes,
+ selectedModeId,
+ onSelect,
+ label,
+}: ModeSelectorProps) {
+ const selected = modes.find((mode) => mode.id === selectedModeId)
+ const currentLabel = selected?.name ?? selectedModeId ?? ""
+ return (
+
+
+
+
+
+
+
+
+ {modes.map((mode) => (
+
+
+
+ ))}
+
+
+
+ )
+}
diff --git a/src/components/conversations/conversation-detail-header.tsx b/src/components/conversations/conversation-detail-header.tsx
index 4f1c8717d1..49a75ed255 100644
--- a/src/components/conversations/conversation-detail-header.tsx
+++ b/src/components/conversations/conversation-detail-header.tsx
@@ -22,6 +22,7 @@ import {
} from "@/lib/api"
import { formatConversationTitle } from "@/lib/conversation-title"
import { RENAME_CONVERSATION_EVENT } from "@/lib/rename-conversation-events"
+import { DELETE_CONVERSATION_EVENT } from "@/lib/floating-ball-session-events"
import { ConversationHeaderFolderPicker } from "@/components/chat/conversation-context-bar"
import { useAppWorkspaceStore } from "@/stores/app-workspace-store"
import { useTabActions } from "@/contexts/tab-context"
@@ -65,6 +66,7 @@ import {
import { SessionDetailsDialog } from "./session-details-dialog"
import { ConversationHeaderTags } from "./conversation-tag-picker"
import { useIsMobile } from "@/hooks/use-mobile"
+import { forgetRecentConversation } from "@/lib/recent-sessions-prefs"
interface ConversationDetailHeaderProps {
tabId: string
@@ -228,6 +230,20 @@ export const ConversationDetailHeader = memo(function ConversationDetailHeader({
return () => window.removeEventListener(RENAME_CONVERSATION_EVENT, onRename)
}, [conversationId, renameTarget, title])
+ // Floating-ball "delete session": reuse this header's existing confirm
+ // dialog instead of minting a second one (same multi-tab idiom as rename).
+ useEffect(() => {
+ if (conversationId == null) return
+ const onDelete = (e: Event) => {
+ const id = (e as CustomEvent<{ conversationId: number | null }>).detail
+ ?.conversationId
+ if (id !== conversationId || deleteTarget != null) return
+ setDeleteTarget({ id: conversationId, tabId, title: displayTitle })
+ }
+ window.addEventListener(DELETE_CONVERSATION_EVENT, onDelete)
+ return () => window.removeEventListener(DELETE_CONVERSATION_EVENT, onDelete)
+ }, [conversationId, deleteTarget, tabId, displayTitle])
+
const handleStatusChange = useCallback(
(next: ConversationStatus) => {
if (conversationId == null) return
@@ -249,6 +265,9 @@ export const ConversationDetailHeader = memo(function ConversationDetailHeader({
if (deleteTarget == null) return
try {
await deleteConversation(deleteTarget.id)
+ // Keep the floating ball's recent-sessions LRU from cycling into a
+ // conversation that no longer exists.
+ forgetRecentConversation(deleteTarget.id)
// The deleted conversation is gone — close its tab and refresh the list.
// Not recorded for reopen: there is no longer a conversation to reopen.
closeTab(deleteTarget.tabId, { recordForReopen: false })
diff --git a/src/components/conversations/conversation-detail-panel.tsx b/src/components/conversations/conversation-detail-panel.tsx
index 3ac574c9bb..863077da99 100644
--- a/src/components/conversations/conversation-detail-panel.tsx
+++ b/src/components/conversations/conversation-detail-panel.tsx
@@ -145,6 +145,12 @@ import {
getSavedModeId,
saveModePreference,
} from "@/lib/selector-prefs-storage"
+import { matchFullAccessMode } from "@/lib/default-mode-prefs"
+import {
+ eventMatchesConversation,
+ FOCUS_MODE_SELECTOR_EVENT,
+ TOGGLE_PLAN_FULL_EVENT,
+} from "@/lib/floating-ball-session-events"
import {
adoptLegacyNewConversationDraft,
buildConversationDraftStorageKey,
@@ -273,6 +279,7 @@ const ConversationTabView = memo(function ConversationTabView({
// Composer-namespace copy for the queue row's click-to-insert outcomes
// (same keys the composer's own mid-turn send reports).
const tCmp = useTranslations("Folder.chat.messageInput")
+ const tBall = useTranslations("FloatingBall")
const tWelcome = useTranslations("Folder.chat.welcomeInputPanel")
const tDiag = useTranslations("DiagnosticsSettings")
const sharedT = useTranslations("Folder.chat.shared")
@@ -1624,6 +1631,63 @@ const ConversationTabView = memo(function ConversationTabView({
[effectiveModes, selectedAgent]
)
+ // Floating-ball "Plan ⇄ full access": classify the advertised modes into a
+ // plan side and a full-access side (id substring weights, same helper the
+ // default-mode logic uses), then hop to the other side. Falls through to
+ // Plan when the current mode is neither; toasts when Plan doesn't exist.
+ const handleTogglePlanFull = useCallback(() => {
+ const availableModes = effectiveModes?.available_modes ?? []
+ if (availableModes.length === 0) {
+ toast.info(tBall("toasts.noModesAvailable"))
+ return
+ }
+ const current = selectedModeIdRef.current
+ const availableIds = availableModes.map((m) => m.id)
+ const planId = availableIds.find((id) => id.toLowerCase().includes("plan"))
+ const fullId = matchFullAccessMode(availableIds)
+ const target =
+ current != null && planId != null && current === planId
+ ? (fullId ?? null)
+ : planId
+ if (target == null) {
+ toast.info(tBall("toasts.noSwitchTarget"))
+ return
+ }
+ handleModeChange(target)
+ // Sync the agent immediately — a mode change should not wait for the next
+ // send's catch-up diff, especially for the full-access side.
+ if (target !== conn.modes?.current_mode_id) {
+ void acpActions.setMode(tabId, target).catch((err) => {
+ console.error("[ConversationDetailPanel] fb setMode:", err)
+ })
+ }
+ }, [acpActions, conn.modes, effectiveModes, handleModeChange, tabId, tBall])
+
+ // Floating-ball hand-offs (delete → header's confirm dialog; mode selector /
+ // plan toggle → this panel's composer). Events carry the DB id and every
+ // mounted panel instance hears them — only the one whose conversation
+ // matches reacts (multi-tab safe, same idiom as rename).
+ const [modeSelectorSignal, setModeSelectorSignal] = useState(0)
+ useEffect(() => {
+ const match = (e: Event) =>
+ eventMatchesConversation(
+ (e as CustomEvent<{ conversationId: number | null }>).detail,
+ dbConversationId
+ )
+ const onFocusMode = (e: Event) => {
+ if (match(e)) setModeSelectorSignal((n) => n + 1)
+ }
+ const onTogglePlan = (e: Event) => {
+ if (match(e)) handleTogglePlanFull()
+ }
+ window.addEventListener(FOCUS_MODE_SELECTOR_EVENT, onFocusMode)
+ window.addEventListener(TOGGLE_PLAN_FULL_EVENT, onTogglePlan)
+ return () => {
+ window.removeEventListener(FOCUS_MODE_SELECTOR_EVENT, onFocusMode)
+ window.removeEventListener(TOGGLE_PLAN_FULL_EVENT, onTogglePlan)
+ }
+ }, [dbConversationId, handleTogglePlanFull])
+
const handleAnswerQuestion = useCallback(
(answer: string) => {
if (connStatus !== "connected") return
@@ -2299,6 +2363,7 @@ const ConversationTabView = memo(function ConversationTabView({
return (
@@ -2474,6 +2539,7 @@ const ConversationTabView = memo(function ConversationTabView({
) : null}
({
vi.mock("@/contexts/acp-connections-context", () => ({
useAcpActions: () => ({ cancel: vi.fn() }),
// Not a zustand store: it returns the context value directly.
- useConnectionStore: () => ({ getActiveKey: () => null }),
+ useConnectionStore: () => ({
+ getActiveKey: () => null,
+ getConnection: () => null,
+ }),
}))
vi.mock("@/hooks/use-appearance", () => ({
useZoomLevel: () => ({ zoomLevel: 100, setZoomLevel: vi.fn() }),
@@ -116,6 +119,11 @@ vi.mock("@/contexts/tab-context", () => ({
selector: (s: {
tabs: { id: string; conversationId: number | null; agentType: string }[]
activeTabId: string | null
+ rawTabs: {
+ id: string
+ conversationId: number | null
+ agentType: string
+ }[]
}) => T
) =>
selector({
@@ -125,6 +133,12 @@ vi.mock("@/contexts/tab-context", () => ({
: [{ id: state.activeTabId, conversationId: 7, agentType: "zcode" }]
: [],
activeTabId: state.activeTabId,
+ rawTabs:
+ state.activeTabId && state.activeTab
+ ? [state.activeTab]
+ : state.activeTabId
+ ? [{ id: state.activeTabId, conversationId: 7, agentType: "zcode" }]
+ : [],
}),
}))
vi.mock("@/contexts/workspace-context", () => ({
@@ -161,7 +175,8 @@ vi.mock("@/hooks/use-shortcut-settings", () => ({
}))
vi.mock("@/stores/app-workspace-store", () => ({
isConversationDeleted: () => false,
- useAppWorkspaceStore: { getState: () => ({ getFolder: () => null }) },
+ useAppWorkspaceStore: (selector: (s: { conversations: [] }) => unknown) =>
+ selector({ conversations: [] }),
}))
vi.mock("@/lib/closed-tab-stack", () => ({ popClosedTab: () => null }))
vi.mock("@/components/conversations/search-command-dialog", () => ({
diff --git a/src/components/layout/workspace-chrome-controller.tsx b/src/components/layout/workspace-chrome-controller.tsx
index 54a290df78..e6db93539a 100644
--- a/src/components/layout/workspace-chrome-controller.tsx
+++ b/src/components/layout/workspace-chrome-controller.tsx
@@ -1,7 +1,11 @@
"use client"
import { useCallback, useEffect, useRef, useState } from "react"
-import { openSettingsWindow } from "@/lib/api"
+import {
+ openSettingsWindow,
+ openImportSessionsWindow,
+ updateConversationPinned,
+} from "@/lib/api"
import {
useAcpActions,
useConnectionStore,
@@ -16,6 +20,15 @@ import { useSortedAvailableAgents } from "@/hooks/use-sorted-available-agents"
import { useTabActions, useTabStore } from "@/contexts/tab-context"
import { requestCreateTaskFromText } from "@/lib/task-compose-events"
import { requestRenameConversation } from "@/lib/rename-conversation-events"
+import {
+ requestDeleteConversation,
+ requestFocusModeSelector,
+ requestTogglePlanFull,
+} from "@/lib/floating-ball-session-events"
+import {
+ nextRecentConversation,
+ readRecentSessionDepth,
+} from "@/lib/recent-sessions-prefs"
import {
useWorkspaceActions,
useWorkspaceFileTabs,
@@ -91,6 +104,11 @@ export function WorkspaceChromeController() {
useTabActions()
const tabs = useTabStore((s) => s.tabs)
const activeTabId = useTabStore((s) => s.activeTabId)
+ // cycleRecentSessions picks from the localStorage LRU queue; isAvailable
+ // filters to conversations this window can actually open (cross-window
+ // pollution guard: the queue is shared, the tabs are per-window).
+ const conversations = useAppWorkspaceStore((s) => s.conversations)
+ const rawTabs = useTabStore((s) => s.rawTabs)
// Tab-close/navigation shortcuts used to live in the visible tab strips.
// Mobile no longer mounts those strips, so this always-mounted controller now
// owns them too (see the keydown handler below).
@@ -113,7 +131,7 @@ export function WorkspaceChromeController() {
// whichever conversation happens to be mounted. The active connection is
// what the workspace considers "the turn in front of the user".
const { cancel } = useAcpActions()
- const { getActiveKey } = useConnectionStore()
+ const { getActiveKey, getConnection } = useConnectionStore()
// Agent cycling (floating ball "next agent" / "favorite agents") needs the
// same enabled+available list the draft tabs resolve their defaults from.
const { sortedTypes: sortedAvailableAgents } = useSortedAvailableAgents()
@@ -606,6 +624,92 @@ export function WorkspaceChromeController() {
confirmDraftAgent(tab.id, next)
return
}
+ case "openBallBindings":
+ void openSettingsWindow("appearance").catch((err) => {
+ console.error(
+ "[WorkspaceChromeController] appearance settings:",
+ err
+ )
+ })
+ return
+ case "openCollaboration":
+ void openSettingsWindow("collaboration").catch((err) => {
+ console.error(
+ "[WorkspaceChromeController] collaboration settings:",
+ err
+ )
+ })
+ return
+ case "openImportSessions":
+ void openImportSessionsWindow().catch((err) => {
+ console.error("[WorkspaceChromeController] import sessions:", err)
+ })
+ return
+ case "deleteCurrentConversation":
+ requestDeleteConversation(activeTab?.conversationId ?? null)
+ return
+ case "togglePinConversation": {
+ const conv = conversations.find(
+ (c) => c.id === activeTab?.conversationId
+ )
+ if (!conv) {
+ toast.info(tBall("toasts.renameNeedsSavedSession"))
+ return
+ }
+ void updateConversationPinned(conv.id, conv.pinned_at == null)
+ .then(() => toast.info(tBall("toasts.pinToggled")))
+ .catch((err) => {
+ console.error("[WorkspaceChromeController] pin toggle:", err)
+ })
+ return
+ }
+ case "focusModeSelector":
+ requestFocusModeSelector(activeTab?.conversationId ?? null)
+ return
+ case "togglePlanFullAccess":
+ requestTogglePlanFull(activeTab?.conversationId ?? null)
+ return
+ case "cycleRunningSessions": {
+ // "Running" = this window's connections currently generating. The
+ // connection store is per-window, so a session streaming in another
+ // window is invisible here — the toast phrasing accounts for that.
+ const runningTabs = rawTabs.filter(
+ (tab) => getConnection(tab.id)?.status === "prompting"
+ )
+ if (runningTabs.length === 0) {
+ toast.info(tBall("toasts.noRunningSession"))
+ return
+ }
+ if (runningTabs.length <= 1) {
+ toast.info(tBall("toasts.noOtherRunning"))
+ return
+ }
+ const currentIndex = runningTabs.findIndex(
+ (tab) => tab.id === activeTabId
+ )
+ // Active tab not running → jump to the first running tab; otherwise
+ // step forward through the running set in tab order.
+ const nextIndex = (currentIndex + 1) % runningTabs.length
+ switchTab(runningTabs[nextIndex].id)
+ return
+ }
+ case "cycleRecentSessions": {
+ if (!activeFolder) return
+ const target = nextRecentConversation(
+ activeTab?.conversationId ?? null,
+ readRecentSessionDepth(),
+ (id) =>
+ conversations.some((c) => c.id === id) &&
+ rawTabs.some((tab) => tab.conversationId === id)
+ )
+ if (target == null) {
+ toast.info(tBall("toasts.noOtherRecent"))
+ return
+ }
+ const tab = rawTabs.find((t) => t.conversationId === target)
+ if (tab) switchTab(tab.id)
+ return
+ }
case "panel":
return
}
@@ -617,13 +721,16 @@ export function WorkspaceChromeController() {
auxPanel,
cancel,
confirmDraftAgent,
+ conversations,
favoriteAgents,
getActiveKey,
+ getConnection,
handleOpenFolder,
handleOpenSettings,
openChatModeTab,
openConversations,
openNewConversationTab,
+ rawTabs,
reopenClosedTab,
setSearchOpen,
setRoute,
diff --git a/src/components/settings/appearance-settings.tsx b/src/components/settings/appearance-settings.tsx
index 85c3f33a32..173175e272 100644
--- a/src/components/settings/appearance-settings.tsx
+++ b/src/components/settings/appearance-settings.tsx
@@ -53,6 +53,11 @@ import {
type ThemeColor,
type ZoomLevel,
} from "@/lib/theme-presets"
+import {
+ readRecentSessionDepth,
+ writeRecentSessionDepth,
+ type RecentSessionDepth,
+} from "@/lib/recent-sessions-prefs"
import { PetManagerSection } from "./pet-manager-section"
import { FontSettingsSection } from "./font-settings-section"
import { WorkspaceBackgroundSection } from "./workspace-background-section"
@@ -90,6 +95,15 @@ const BALL_BINDABLE_ACTIONS: readonly FloatingBallAction[] = [
"openSessionFolder",
"cycleAgent",
"cycleFavoriteAgent",
+ "openBallBindings",
+ "cycleRunningSessions",
+ "cycleRecentSessions",
+ "deleteCurrentConversation",
+ "openImportSessions",
+ "togglePinConversation",
+ "focusModeSelector",
+ "togglePlanFullAccess",
+ "openCollaboration",
"zoomIn",
"zoomOut",
"zoomReset",
@@ -104,9 +118,8 @@ function isFloatingBallSize(v: string): v is FloatingBallSize {
/** Label of a gesture's built-in default, for the placeholder row. */
function defaultGestureLabel(
action: FloatingBallAction,
- // Loosely typed: the two caller namespaces (FloatingBall / AppearanceSettings)
- // both mirror the actions.* keys, and next-intl's key union would force a
- // per-namespace overload for no safety gain here.
+ // Loosely typed: callers pass the FloatingBall namespace's t; next-intl's
+ // key union would force a per-key overload for no safety gain here.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
t: any
): string {
@@ -187,10 +200,15 @@ export function AppearanceSettings() {
// 的宽度更小。
const chatWidthMax = chatContentWidthCeiling(screenWidth, zoomLevel / 100)
- // The binding dropdown renders under the AppearanceSettings namespace, whose
- // mirrored actions.* keys come from FloatingBall.
+ // Gesture/action labels come from the FloatingBall namespace — the only one
+ // that actually carries translations; the AppearanceSettings.gestures/actions
+ // mirror is legacy and no longer read here.
+ const ballT = useTranslations("FloatingBall")
+ const [recentSessionDepth, setRecentSessionDepth] = useState(
+ readRecentSessionDepth
+ )
const actionLabel = (action: FloatingBallAction) =>
- action === "panel" ? t("floatingBall.panelTitle") : t(`actions.${action}`)
+ action === "panel" ? ballT("panelTitle") : ballT(`actions.${action}`)
const resolvedThemeLabel =
resolvedTheme === "dark"
@@ -494,7 +512,7 @@ export function AppearanceSettings() {
className="flex items-center justify-between gap-2"
>
- {t(`gestures.${gesture}`, {
+ {ballT(`gestures.${gesture}`, {
fallback: gesture,
})}
@@ -513,9 +531,9 @@ export function AppearanceSettings() {
DEFAULT_FLOATING_BALL_BINDINGS[gesture]
? defaultGestureLabel(
DEFAULT_FLOATING_BALL_BINDINGS[gesture],
- t
+ ballT
)
- : t("floatingBall.bindingCleared")
+ : ballT("bindingCleared")
}
/>
@@ -524,9 +542,9 @@ export function AppearanceSettings() {
{DEFAULT_FLOATING_BALL_BINDINGS[gesture]
? defaultGestureLabel(
DEFAULT_FLOATING_BALL_BINDINGS[gesture],
- t
+ ballT
)
- : t("floatingBall.bindingCleared")}
+ : ballT("bindingCleared")}
{BALL_BINDABLE_ACTIONS.map((action) => (
+
+ {/* Depth of the recent-sessions cycle (2 = toggle between the two
+ most recently opened). Read/written straight to localStorage —
+ the writer lives in tab-store, outside React. */}
+
+
{ballT("recentSessionDepth")}
+
+
{/* ===== Chat content width ===== */}
diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json
index bf854b2c0e..a557656ba3 100644
--- a/src/i18n/messages/ar.json
+++ b/src/i18n/messages/ar.json
@@ -181,6 +181,13 @@
"sectionDescription": "حركات الطي/التوسيع واستدعاءات الأدوات وحالة العمل داخل منطقة المحادثة، إضافةً إلى التمرير السلس. عند الإيقاف تتحدّث الواجهة فورًا. تستمر مؤشرات التحميل في الدوران.",
"enable": "تفعيل حركات المحادثة"
},
+ "messageNav": {
+ "sectionTitle": "مستكشف الرسائل",
+ "sectionDescription": "موضع مستكشف رسائل المحادثة. عند اختيار أسفل اليمين يصبح بطاقة مُدمجة بسطر واحد لكل رسالة مستخدم فوق حقل الإدخال.",
+ "positionStart": "أعلى اليسار (افتراضي)",
+ "positionBottomEnd": "أسفل اليمين (مُدمج)",
+ "hint": "تبقى لوحتا الخطة والوكلاء الفرعيين في أعلى اليسار في كل الأحوال."
+ },
"chatWidth": {
"sectionTitle": "عرض المحادثة",
"sectionDescription": "أقصى عرض لعمود المحادثة ومربع الإدخال. يمكنك أيضًا سحب حافتي منطقة المحادثة لضبطه.",
@@ -258,60 +265,69 @@
"panelTitle": "إجراءات سريعة"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "نقرة",
+ "doubleTap": "نقرة مزدوجة",
+ "longPress": "ضغط مطول",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ ثم ←",
+ "upThenRight": "↑ ثم →",
+ "upDown": "↑ ثم ↓",
+ "leftThenRight": "← ثم →",
+ "rightThenLeft": "→ ثم ←",
+ "upLeftThenDown": "↖ ثم ↓",
+ "upRightThenDown": "↗ ثم ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ ثم ↑",
+ "upThenDownRight": "↑ ثم ↘",
+ "downThenUpRight": "↓ ثم ↗",
+ "rightThenUp": "→ ثم ↑",
+ "rightThenDown": "→ ثم ↓",
+ "downThenRight": "↓ ثم →",
+ "downThenLeft": "↓ ثم ←",
+ "downRightThenUp": "↘ ثم ↑",
+ "downLeftThenUp": "↙ ثم ↑",
+ "upLeftThenRight": "↖ ثم →",
+ "upRightThenLeft": "↗ ثم ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
- "openCanvas": "Canvas",
- "openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "newConversation": "محادثة جديدة",
+ "toggleSidebar": "تبديل الشريط الجانبي",
+ "toggleSearch": "بحث",
+ "toggleTerminal": "تبديل الطرفية",
+ "nextTab": "التبويب التالي",
+ "prevTab": "التبويب السابق",
+ "reopenClosedTab": "إعادة فتح التبويب المغلق",
+ "openFolder": "فتح مجلد",
+ "zoomIn": "تكبير",
+ "zoomOut": "تصغير",
+ "zoomReset": "إعادة تعيين التكبير",
+ "stopGenerating": "إيقاف التوليد",
+ "openSettings": "الإعدادات",
+ "openTodos": "المهام",
+ "openTodosNew": "مهمة جديدة",
+ "openAutomations": "الأتمتة",
+ "openCanvas": "اللوحة",
+ "openAgents": "الوكلاء",
+ "openSystemAdmin": "إدارة النظام",
+ "renameConversation": "إعادة تسمية المحادثة",
+ "openSessionFolder": "ملفات الجلسة",
+ "cycleAgent": "الوكيل التالي",
+ "cycleFavoriteAgent": "الوكلاء المفضلون",
+ "openBallBindings": "ربط الإيماءات",
+ "cycleRunningSessions": "الجلسات الجارية",
+ "cycleRecentSessions": "الجلسات الأخيرة",
+ "deleteCurrentConversation": "حذف الجلسة الحالية",
+ "openImportSessions": "استيراد الجلسات",
+ "togglePinConversation": "تثبيت / إلغاء التثبيت",
+ "focusModeSelector": "محدد الوضع",
+ "togglePlanFullAccess": "خطة / وصول كامل",
+ "openCollaboration": "التعاون"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "يُمرَّر إلى CLI باسم KIRO_API_KEY. اتركه فارغاً لاستخدام الحساب الذي سجلت الدخول به عبر kiro-cli login؛ لا يلزم إلا حيث يتعذر تسجيل الدخول بالمتصفح (الخوادم، Docker).",
"saveConfig": "حفظ إعدادات Kiro"
},
- "trae": {
- "configManagement": "إدارة الإعدادات",
- "configDescription": "يتوفر TRAE CLI 2.0 لعملاء الخطة الرئيسية من TRAE Enterprise فقط. يشغّل Codeg أداة traecli التي ثبّتّها، وهي تحفظ تسجيل الدخول والمهارات وخوادم MCP في ~/.trae. النموذج والوضع ومستوى الاستدلال ليست هنا: يُبلغ عنها TRAE CLI عبر ACP، لذا تديرها محددات المحرّر لكل جلسة.",
- "signInTitle": "تسجيل الدخول",
- "signInHint": "شغّل هذا الأمر مرة واحدة في الطرفية لتسجيل الدخول عبر SSO الخاص بمؤسستك. تعيد جلسات Codeg استخدام تسجيل الدخول هذا.",
- "copyCommand": "نسخ الأمر",
- "commandCopied": "تم نسخ الأمر",
- "patLabel": "رمز الوصول الشخصي (اختياري)",
- "patHint": "للأجهزة التي يتعذر فيها تسجيل الدخول بالمتصفح، مثل الخوادم أو تثبيتات Docker. يمرّره Codeg إلى TRAE CLI باسم TRAECLI_PERSONAL_ACCESS_TOKEN ويسجّل الدخول به عند بدء كل جلسة. اتركه فارغاً لاستخدام تسجيل الدخول من traecli login.",
- "hostLabel": "عنوان API الخاص بالمؤسسة (اختياري)",
- "hostHint": "فقط إذا كانت مؤسستك تشغّل TRAE على نطاقها الخاص. يُمرَّر باسم TRAECLI_HOST؛ اتركه فارغاً لاستخدام خدمة TRAE نفسها.",
- "saveConfig": "حفظ إعدادات TRAE CLI"
- },
- "commandCode": {
- "configManagement": "إدارة الإعدادات",
- "configDescription": "يشغّل Codeg واجهة Command Code CLI من حزمة npm المسماة command-code، وهي تحفظ تسجيل الدخول والمهارات وخوادم MCP في ~/.commandcode. النموذج والوضع ومستوى الاستدلال ليست هنا: يُبلغ عنها Command Code عبر ACP، لذا تديرها محددات المحرّر لكل جلسة.",
- "signInTitle": "تسجيل الدخول",
- "signInHint": "شغّل هذا الأمر مرة واحدة في الطرفية لتسجيل الدخول بحساب Command Code الخاص بك. تعيد جلسات Codeg استخدام تسجيل الدخول هذا.",
- "copyCommand": "نسخ الأمر",
- "commandCopied": "تم نسخ الأمر",
- "apiKeyLabel": "مفتاح API (اختياري)",
- "apiKeyHint": "للأجهزة التي يتعذر فيها تسجيل الدخول بالمتصفح، مثل الخوادم أو تثبيتات Docker. يُمرَّر إلى Command Code باسم COMMAND_CODE_API_KEY ويتقدّم على تسجيل الدخول من command-code login. اتركه فارغاً لاستخدام تسجيل الدخول ذاك.",
- "saveConfig": "حفظ إعدادات Command Code"
- },
"deepseek": {
"configManagement": "إعدادات DeepSeek Harness",
"configDescription": "نقطة النهاية والمفتاح متغيّرا بيئة يقرأهما deepseek-acp عند الإقلاع. أما النموذج ومستوى الاستدلال فمحدِّدان على مستوى الجلسة، ويُختاران من حقل الإدخال.",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "تم حفظ إعدادات Kiro",
"saveKiroFailed": "تعذّر حفظ إعدادات Kiro",
- "traeSaved": "تم حفظ إعدادات TRAE CLI",
- "saveTraeFailed": "تعذّر حفظ إعدادات TRAE CLI",
- "commandCodeSaved": "تم حفظ إعدادات Command Code",
- "saveCommandCodeFailed": "تعذّر حفظ إعدادات Command Code",
"systemAgentAlreadyLatest": "{name} محدَّث بالفعل ({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "الالتزامات"
},
"noFolderTitle": "لا يوجد مجلد مفتوح",
- "noFolderHint": "افتح مجلدا لعرض محتواه هنا",
- "openFullPage": "فتح في صفحة كاملة",
- "back": "رجوع",
- "noAutomations": "لا توجد أتمتة لهذا المشروع بعد"
+ "noFolderHint": "افتح مجلدا لعرض محتواه هنا"
},
"windowControls": {
"minimizeWindow": "تصغير النافذة",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "اسأل أي شيء...",
- "promptSuggestion": "{suggestion} (اضغط Tab للاستخدام)",
"removeAttachmentAria": "إزالة {name}",
"attachFiles": "إرفاق ملفات",
"addActions": "إضافة",
@@ -3411,10 +3395,6 @@
"searchModelAria": "البحث عن النماذج",
"modelListLabel": "النماذج",
"recommendedBadge": "موصى به",
- "recommendedValue": "موصى به: {value}",
- "searchOptions": "البحث في الخيارات...",
- "searchOptionsAria": "البحث في الخيارات",
- "noOptions": "لم يتم العثور على خيارات",
"noModels": "لم يتم العثور على نماذج",
"cancel": "إلغاء",
"send": "إرسال",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "تنقل الرسائل",
+ "collapse": "طي تنقل الرسائل",
"loadingEarlier": "جارٍ تحميل الرسائل السابقة…",
"loadEarlier": "تحميل الرسائل السابقة",
+ "collapsedSummary": "الرسائل {count}",
"fileCount": "{count, plural, one {# ملف} other {# ملفات}}",
- "subAgentCount": "{count, plural, one {# وكيل فرعي} other {# وكلاء فرعيين}}",
- "showDiff": "إظهار تغييرات {filePath}",
- "hideDiff": "إخفاء تغييرات {filePath}",
- "openFile": "فتح {filePath}",
- "collapse": "طي",
- "currentMessage": "الرسالة الحالية",
- "scrollToCurrent": "التمرير إلى الرسالة الحالية (#{ordinal})"
+ "remove": "إزالة",
+ "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}"
},
"replyArtifacts": {
"title": "الملفات المتغيرة",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "استئناف المهمة {task}",
"resumeDelegationNoId": "استئناف مهمة مفوضة",
"promptLabel": "التعليمات",
- "ackRecorded": "سُجِّل في مهمة العمل",
- "ackNotRecorded": "لم يُسجَّل في مهمة العمل",
- "ackNotRecordedWithReason": "لم يُسجَّل في مهمة العمل: {reason}",
"verdict": {
"success": "ناجحة",
"needs_review": "بحاجة إلى مراجعة",
@@ -4214,18 +4188,6 @@
"stopDeclined": "تعذّر إيقاف هذه المهمة، ربما تكون قد انتهت بالفعل.",
"stopFailed": "فشل إيقاف المهمة: {error}"
},
- "remoteControl": {
- "title": "التحكم عن بُعد مُفعّل",
- "open": "فتح في المتصفح",
- "copy": "نسخ الرابط",
- "copied": "تم النسخ",
- "qr": "رمز QR",
- "qrLabel": "رمز QR لرابط التحكم عن بُعد لهذه الجلسة",
- "qrHint": "امسحه بهاتفك لمتابعة هذه الجلسة في تطبيق Claude أو على claude.ai/code.",
- "noUrl": "لم يُرجع Claude Code رابطًا لهذه الجلسة",
- "turnOff": "إيقاف",
- "turnOffBusy": "متاح بعد أن ينتهي Claude"
- },
"proposedPlan": {
"title": "الخطة المقترحة",
"planning": "جارٍ التخطيط…"
@@ -7433,44 +7395,62 @@
"renameConversation": "إعادة تسمية المحادثة",
"openSessionFolder": "ملفات الجلسة",
"cycleAgent": "الوكيل التالي",
- "cycleFavoriteAgent": "الوكلاء المفضلون"
+ "cycleFavoriteAgent": "الوكلاء المفضلون",
+ "openBallBindings": "ربط الإيماءات",
+ "cycleRunningSessions": "الجلسات الجارية",
+ "cycleRecentSessions": "الجلسات الأخيرة",
+ "deleteCurrentConversation": "حذف الجلسة الحالية",
+ "openImportSessions": "استيراد الجلسات",
+ "togglePinConversation": "تثبيت / إلغاء التثبيت",
+ "focusModeSelector": "محدد الوضع",
+ "togglePlanFullAccess": "خطة / وصول كامل",
+ "openCollaboration": "التعاون"
},
"gestures": {
"tap": "نقرة",
"doubleTap": "نقرة مزدوجة",
- "longPress": "ضغط مطوّل",
- "left": "سحب لليسار",
- "right": "سحب لليمين",
- "up": "سحب للأعلى",
- "upLeft": "أعلى اليسار",
- "upRight": "أعلى اليمين",
- "upThenLeft": "أعلى ثم يسار",
- "upThenRight": "أعلى ثم يمين",
- "upDown": "أعلى ثم أسفل",
- "leftThenRight": "يسار ثم يمين",
- "rightThenLeft": "يمين ثم يسار",
- "upLeftThenDown": "أعلى اليسار ثم أسفل",
- "upRightThenDown": "أعلى اليمين ثم أسفل",
- "down": "اسحب لأسفل",
- "downLeft": "أسفل-يسار",
- "downRight": "أسفل-يمين",
- "downUp": "أسفل ثم أعلى",
- "upThenDownRight": "أعلى ثم أسفل-يمين",
- "downThenUpRight": "أسفل ثم أعلى-يمين",
- "rightThenUp": "يمين ثم أعلى",
- "rightThenDown": "يمين ثم أسفل",
- "downThenRight": "أسفل ثم يمين",
- "downThenLeft": "أسفل ثم يسار",
- "downRightThenUp": "أسفل-يمين ثم أعلى",
- "downLeftThenUp": "أسفل-يسار ثم أعلى",
- "upLeftThenRight": "أعلى-يسار ثم يمين",
- "upRightThenLeft": "أعلى-يمين ثم يسار"
+ "longPress": "ضغط مطول",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ ثم ←",
+ "upThenRight": "↑ ثم →",
+ "upDown": "↑ ثم ↓",
+ "leftThenRight": "← ثم →",
+ "rightThenLeft": "→ ثم ←",
+ "upLeftThenDown": "↖ ثم ↓",
+ "upRightThenDown": "↗ ثم ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ ثم ↑",
+ "upThenDownRight": "↑ ثم ↘",
+ "downThenUpRight": "↓ ثم ↗",
+ "rightThenUp": "→ ثم ↑",
+ "rightThenDown": "→ ثم ↓",
+ "downThenRight": "↓ ثم →",
+ "downThenLeft": "↓ ثم ←",
+ "downRightThenUp": "↘ ثم ↑",
+ "downLeftThenUp": "↙ ثم ↑",
+ "upLeftThenRight": "↖ ثم →",
+ "upRightThenLeft": "↗ ثم ←"
},
"favoriteAgentsEmpty": "لا يوجد وكلاء متاحون",
"toasts": {
"renameNeedsSavedSession": "إعادة التسمية تعمل على الجلسات المحفوظة فقط — أرسل رسالة أولاً.",
"sessionFolderNeedsWorkspace": "افتح مجلد مساحة العمل أولاً.",
- "cycleNeedsMoreAgents": "وكيل واحد متاح فقط — لا يوجد ما يمكن التبديل إليه."
- }
+ "cycleNeedsMoreAgents": "وكيل واحد متاح فقط — لا يوجد ما يمكن التبديل إليه.",
+ "noOtherRunning": "لا توجد جلسة جارية أخرى.",
+ "noOtherRecent": "لا توجد جلسة حديثة أخرى.",
+ "noPlanMode": "لا يحتوي هذا الوكيل على وضع الخطة.",
+ "pinToggled": "تم تحديث حالة التثبيت.",
+ "noRunningSession": "لا توجد جلسة جارية بعد.",
+ "noModesAvailable": "لا يوفر هذا الوكيل أي أوضاع.",
+ "noSwitchTarget": "لا يوجد وضع للتبديل إليه (لم يتم العثور على وضع Plan أو الوصول الكامل)."
+ },
+ "recentSessionDepth": "عمق تبديل الجلسات الأخيرة",
+ "bindingCleared": "غير مربوط"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json
index f9c30e597f..cf581c7fb1 100644
--- a/src/i18n/messages/de.json
+++ b/src/i18n/messages/de.json
@@ -181,6 +181,13 @@
"sectionDescription": "Animationen für Ein-/Ausklappen, Tool-Aufrufe und Arbeitsstatus im Unterhaltungsbereich sowie sanftes Scrollen. Wenn deaktiviert, werden Änderungen sofort angezeigt. Ladeanzeigen drehen sich weiterhin.",
"enable": "Chat-Animationen aktivieren"
},
+ "messageNav": {
+ "sectionTitle": "Nachrichten-Navigator",
+ "sectionDescription": "Position des Nachrichten-Navigators. Unten rechts wird er zu einer kompakten Karte mit einer Zeile pro Nutzernachricht über dem Eingabefeld.",
+ "positionStart": "Oben links (Standard)",
+ "positionBottomEnd": "Unten rechts (kompakt)",
+ "hint": "Plan- und Subagenten-Panels bleiben in beiden Fällen oben links."
+ },
"chatWidth": {
"sectionTitle": "Chat-Breite",
"sectionDescription": "Maximale Breite der Unterhaltungsspalte und des Eingabefelds. Sie lässt sich auch durch Ziehen der Chat-Ränder anpassen.",
@@ -258,60 +265,69 @@
"panelTitle": "Schnellaktionen"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "Tippen",
+ "doubleTap": "Doppelt tippen",
+ "longPress": "Lange drücken",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ dann ←",
+ "upThenRight": "↑ dann →",
+ "upDown": "↑ dann ↓",
+ "leftThenRight": "← dann →",
+ "rightThenLeft": "→ dann ←",
+ "upLeftThenDown": "↖ dann ↓",
+ "upRightThenDown": "↗ dann ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ dann ↑",
+ "upThenDownRight": "↑ dann ↘",
+ "downThenUpRight": "↓ dann ↗",
+ "rightThenUp": "→ dann ↑",
+ "rightThenDown": "→ dann ↓",
+ "downThenRight": "↓ dann →",
+ "downThenLeft": "↓ dann ←",
+ "downRightThenUp": "↘ dann ↑",
+ "downLeftThenUp": "↙ dann ↑",
+ "upLeftThenRight": "↖ dann →",
+ "upRightThenLeft": "↗ dann ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
+ "newConversation": "Neue Unterhaltung",
+ "toggleSidebar": "Seitenleiste umschalten",
+ "toggleSearch": "Suchen",
+ "toggleTerminal": "Terminal umschalten",
+ "nextTab": "Nächster Tab",
+ "prevTab": "Vorheriger Tab",
+ "reopenClosedTab": "Geschlossenen Tab wieder öffnen",
+ "openFolder": "Ordner öffnen",
+ "zoomIn": "Vergrößern",
+ "zoomOut": "Verkleinern",
+ "zoomReset": "Zoom zurücksetzen",
+ "stopGenerating": "Generierung stoppen",
+ "openSettings": "Einstellungen",
+ "openTodos": "Aufgaben",
+ "openTodosNew": "Neue Aufgabe",
+ "openAutomations": "Automatisierungen",
"openCanvas": "Canvas",
- "openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "openAgents": "Agenten",
+ "openSystemAdmin": "Systemverwaltung",
+ "renameConversation": "Unterhaltung umbenennen",
+ "openSessionFolder": "Sitzungsdateien",
+ "cycleAgent": "Nächster Agent",
+ "cycleFavoriteAgent": "Favoriten-Agenten",
+ "openBallBindings": "Gesten-Zuordnung",
+ "cycleRunningSessions": "Laufende Sitzungen",
+ "cycleRecentSessions": "Letzte Sitzungen",
+ "deleteCurrentConversation": "Aktuelle Sitzung löschen",
+ "openImportSessions": "Sitzungen importieren",
+ "togglePinConversation": "Anpinnen / lösen",
+ "focusModeSelector": "Modus-Auswahl",
+ "togglePlanFullAccess": "Plan / Vollzugriff",
+ "openCollaboration": "Kollaboration"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "Wird der CLI als KIRO_API_KEY übergeben. Leer lassen, um das per kiro-cli login angemeldete Konto zu nutzen; nur nötig, wo keine Browser-Anmeldung möglich ist (Server, Docker).",
"saveConfig": "Kiro-Konfiguration speichern"
},
- "trae": {
- "configManagement": "Konfiguration",
- "configDescription": "TRAE CLI 2.0 steht nur Kunden des Flaggschiff-Tarifs von TRAE Enterprise zur Verfügung. Codeg startet das von dir installierte traecli, das Anmeldung, Skills und MCP-Server in ~/.trae speichert. Modell, Modus und Denkaufwand stehen nicht hier: TRAE CLI meldet sie über ACP, daher verwalten die Auswahlfelder im Eingabebereich sie pro Sitzung.",
- "signInTitle": "Anmelden",
- "signInHint": "Führe dies einmal in einem Terminal aus, um dich mit dem SSO deines Unternehmens anzumelden. Sitzungen in Codeg verwenden diese Anmeldung wieder.",
- "copyCommand": "Befehl kopieren",
- "commandCopied": "Befehl kopiert",
- "patLabel": "Persönliches Zugriffstoken (optional)",
- "patHint": "Für Rechner, auf denen keine Browser-Anmeldung möglich ist, etwa Server oder Docker-Installationen. Codeg übergibt es TRAE CLI als TRAECLI_PERSONAL_ACCESS_TOKEN und meldet sich bei jedem Sitzungsstart damit an. Leer lassen, um die Anmeldung aus traecli login zu nutzen.",
- "hostLabel": "Enterprise-API-URL (optional)",
- "hostHint": "Nur wenn deine Organisation TRAE unter einer eigenen Domain betreibt. Wird als TRAECLI_HOST übergeben; leer lassen für den Dienst von TRAE.",
- "saveConfig": "TRAE CLI-Konfiguration speichern"
- },
- "commandCode": {
- "configManagement": "Konfiguration",
- "configDescription": "Codeg startet die Command Code CLI aus dem npm-Paket command-code, die Anmeldung, Skills und MCP-Server in ~/.commandcode speichert. Modell, Modus und Denkaufwand stehen nicht hier: Command Code meldet sie über ACP, daher verwalten die Auswahlfelder im Eingabebereich sie pro Sitzung.",
- "signInTitle": "Anmelden",
- "signInHint": "Führe dies einmal in einem Terminal aus, um dich mit deinem Command Code-Konto anzumelden. Sitzungen in Codeg verwenden diese Anmeldung wieder.",
- "copyCommand": "Befehl kopieren",
- "commandCopied": "Befehl kopiert",
- "apiKeyLabel": "API-Schlüssel (optional)",
- "apiKeyHint": "Für Rechner, auf denen keine Browser-Anmeldung möglich ist, etwa Server oder Docker-Installationen. Wird Command Code als COMMAND_CODE_API_KEY übergeben und hat Vorrang vor der Anmeldung aus command-code login. Leer lassen, um diese Anmeldung zu nutzen.",
- "saveConfig": "Command Code-Konfiguration speichern"
- },
"deepseek": {
"configManagement": "DeepSeek-Harness-Konfiguration",
"configDescription": "Endpunkt und Schlüssel sind Umgebungsvariablen, die deepseek-acp beim Start liest. Modell und Denkstufe sind Auswahlfelder pro Sitzung — sie werden im Eingabefeld gewählt.",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Kiro-Konfiguration gespeichert",
"saveKiroFailed": "Kiro-Konfiguration konnte nicht gespeichert werden",
- "traeSaved": "TRAE CLI-Konfiguration gespeichert",
- "saveTraeFailed": "TRAE CLI-Konfiguration konnte nicht gespeichert werden",
- "commandCodeSaved": "Command Code-Konfiguration gespeichert",
- "saveCommandCodeFailed": "Command Code-Konfiguration konnte nicht gespeichert werden",
"systemAgentAlreadyLatest": "{name} ist bereits aktuell ({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "Einträge"
},
"noFolderTitle": "Kein Ordner geöffnet",
- "noFolderHint": "Öffnen Sie einen Ordner, um seinen Inhalt hier zu sehen",
- "openFullPage": "Als ganze Seite öffnen",
- "back": "Zurück",
- "noAutomations": "Für dieses Projekt gibt es noch keine Automatisierungen"
+ "noFolderHint": "Öffnen Sie einen Ordner, um seinen Inhalt hier zu sehen"
},
"windowControls": {
"minimizeWindow": "Fenster minimieren",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "Fragen Sie alles...",
- "promptSuggestion": "{suggestion} (Tab zum Übernehmen)",
"removeAttachmentAria": "{name} entfernen",
"attachFiles": "Dateien anhängen",
"addActions": "Hinzufügen",
@@ -3411,10 +3395,6 @@
"searchModelAria": "Modelle suchen",
"modelListLabel": "Modelle",
"recommendedBadge": "Empfohlen",
- "recommendedValue": "Empfohlen: {value}",
- "searchOptions": "Optionen suchen...",
- "searchOptionsAria": "Optionen suchen",
- "noOptions": "Keine Optionen gefunden",
"noModels": "Keine Modelle gefunden",
"cancel": "Abbrechen",
"send": "Senden",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "Nachrichtennavigation",
+ "collapse": "Nachrichtennavigation ausblenden",
"loadingEarlier": "Frühere Nachrichten werden geladen…",
"loadEarlier": "Frühere Nachrichten laden",
+ "collapsedSummary": "Nachrichten {count}",
"fileCount": "{count, plural, one {# Datei} other {# Dateien}}",
- "subAgentCount": "{count, plural, one {# Subagent} other {# Subagenten}}",
- "showDiff": "Änderungen an {filePath} anzeigen",
- "hideDiff": "Änderungen an {filePath} ausblenden",
- "openFile": "{filePath} öffnen",
- "collapse": "Einklappen",
- "currentMessage": "Aktuelle Nachricht",
- "scrollToCurrent": "Zur aktuellen Nachricht (#{ordinal}) scrollen"
+ "remove": "Entfernen",
+ "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}"
},
"replyArtifacts": {
"title": "Geänderte Dateien",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "Aufgabe {task} wird fortgesetzt",
"resumeDelegationNoId": "Delegierte Aufgabe wird fortgesetzt",
"promptLabel": "Anweisung",
- "ackRecorded": "In der Arbeitsaufgabe erfasst",
- "ackNotRecorded": "Nicht in der Arbeitsaufgabe erfasst",
- "ackNotRecordedWithReason": "Nicht in der Arbeitsaufgabe erfasst: {reason}",
"verdict": {
"success": "erfolgreich",
"needs_review": "Prüfung nötig",
@@ -4214,18 +4188,6 @@
"stopDeclined": "Diese Aufgabe konnte nicht gestoppt werden – sie ist möglicherweise bereits beendet.",
"stopFailed": "Aufgabe konnte nicht gestoppt werden: {error}"
},
- "remoteControl": {
- "title": "Fernsteuerung aktiv",
- "open": "Im Browser öffnen",
- "copy": "Link kopieren",
- "copied": "Kopiert",
- "qr": "QR-Code",
- "qrLabel": "QR-Code des Fernsteuerungs-Links dieser Sitzung",
- "qrHint": "Mit dem Handy scannen, um diese Sitzung in der Claude-App oder auf claude.ai/code fortzusetzen.",
- "noUrl": "Claude Code hat keinen Link für diese Sitzung zurückgegeben",
- "turnOff": "Ausschalten",
- "turnOffBusy": "Verfügbar, sobald Claude fertig ist"
- },
"proposedPlan": {
"title": "Vorgeschlagener Plan",
"planning": "Wird geplant…"
@@ -7433,44 +7395,62 @@
"renameConversation": "Unterhaltung umbenennen",
"openSessionFolder": "Sitzungsdateien",
"cycleAgent": "Nächster Agent",
- "cycleFavoriteAgent": "Favoriten-Agenten"
+ "cycleFavoriteAgent": "Favoriten-Agenten",
+ "openBallBindings": "Gesten-Zuordnung",
+ "cycleRunningSessions": "Laufende Sitzungen",
+ "cycleRecentSessions": "Letzte Sitzungen",
+ "deleteCurrentConversation": "Aktuelle Sitzung löschen",
+ "openImportSessions": "Sitzungen importieren",
+ "togglePinConversation": "Anpinnen / lösen",
+ "focusModeSelector": "Modus-Auswahl",
+ "togglePlanFullAccess": "Plan / Vollzugriff",
+ "openCollaboration": "Kollaboration"
},
"gestures": {
"tap": "Tippen",
- "doubleTap": "Doppeltippen",
- "longPress": "Langes Drücken",
- "left": "Nach links wischen",
- "right": "Nach rechts wischen",
- "up": "Nach oben wischen",
- "upLeft": "Oben links",
- "upRight": "Oben rechts",
- "upThenLeft": "Oben, dann links",
- "upThenRight": "Oben, dann rechts",
- "upDown": "Oben, dann unten",
- "leftThenRight": "Links, dann rechts",
- "rightThenLeft": "Rechts, dann links",
- "upLeftThenDown": "Oben links, dann unten",
- "upRightThenDown": "Oben rechts, dann unten",
- "down": "Nach unten",
- "downLeft": "Unten-links",
- "downRight": "Unten-rechts",
- "downUp": "Unten, dann oben",
- "upThenDownRight": "Oben, dann unten-re.",
- "downThenUpRight": "Unten, dann oben-re.",
- "rightThenUp": "Rechts, dann oben",
- "rightThenDown": "Rechts, dann unten",
- "downThenRight": "Unten, dann rechts",
- "downThenLeft": "Unten, dann links",
- "downRightThenUp": "Unten-re., dann oben",
- "downLeftThenUp": "Unten-li., dann oben",
- "upLeftThenRight": "Oben-li., dann rechts",
- "upRightThenLeft": "Oben-re., dann links"
+ "doubleTap": "Doppelt tippen",
+ "longPress": "Lange drücken",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ dann ←",
+ "upThenRight": "↑ dann →",
+ "upDown": "↑ dann ↓",
+ "leftThenRight": "← dann →",
+ "rightThenLeft": "→ dann ←",
+ "upLeftThenDown": "↖ dann ↓",
+ "upRightThenDown": "↗ dann ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ dann ↑",
+ "upThenDownRight": "↑ dann ↘",
+ "downThenUpRight": "↓ dann ↗",
+ "rightThenUp": "→ dann ↑",
+ "rightThenDown": "→ dann ↓",
+ "downThenRight": "↓ dann →",
+ "downThenLeft": "↓ dann ←",
+ "downRightThenUp": "↘ dann ↑",
+ "downLeftThenUp": "↙ dann ↑",
+ "upLeftThenRight": "↖ dann →",
+ "upRightThenLeft": "↗ dann ←"
},
"favoriteAgentsEmpty": "Keine Agenten verfügbar",
"toasts": {
"renameNeedsSavedSession": "Umbenennen gilt nur für gespeicherte Sitzungen – senden Sie zuerst eine Nachricht.",
"sessionFolderNeedsWorkspace": "Öffnen Sie zuerst einen Arbeitsbereich-Ordner.",
- "cycleNeedsMoreAgents": "Nur ein Agent verfügbar – nichts zum Wechseln."
- }
+ "cycleNeedsMoreAgents": "Nur ein Agent verfügbar – nichts zum Wechseln.",
+ "noOtherRunning": "Keine weitere laufende Sitzung.",
+ "noOtherRecent": "Keine weitere letzte Sitzung.",
+ "noPlanMode": "Dieser Agent hat keinen Plan-Modus.",
+ "pinToggled": "Pin-Status aktualisiert.",
+ "noRunningSession": "Noch keine laufende Sitzung.",
+ "noModesAvailable": "Dieser Agent stellt keine Modi bereit.",
+ "noSwitchTarget": "Kein Modus zum Wechseln gefunden (Plan- oder Vollzugriffsmodus fehlt)."
+ },
+ "recentSessionDepth": "Umschalttiefe letzte Sitzungen",
+ "bindingCleared": "Nicht zugewiesen"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 631faac6cf..5a5cf2ac7b 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -181,6 +181,13 @@
"sectionDescription": "Entrance, expand/collapse, tool-call and working-status animations in the conversation area, plus smooth scrolling. Turn off for instant, motion-free updates. Spinners keep rotating.",
"enable": "Enable chat animations"
},
+ "messageNav": {
+ "sectionTitle": "Message navigator",
+ "sectionDescription": "Where the per-conversation message navigator sits. Bottom-right keeps it as a compact one-row-per-turn card above the composer, out of the reading column.",
+ "positionStart": "Top-left (default)",
+ "positionBottomEnd": "Bottom-right (compact)",
+ "hint": "Plan and sub-agent panels stay top-left either way."
+ },
"chatWidth": {
"sectionTitle": "Chat width",
"sectionDescription": "Maximum width of the conversation column and the composer. You can also drag the edges of the chat column to adjust it.",
@@ -261,32 +268,32 @@
"tap": "Tap",
"doubleTap": "Double tap",
"longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ then ←",
+ "upThenRight": "↑ then →",
+ "upDown": "↑ then ↓",
+ "leftThenRight": "← then →",
+ "rightThenLeft": "→ then ←",
+ "upLeftThenDown": "↖ then ↓",
+ "upRightThenDown": "↗ then ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ then ↑",
+ "upThenDownRight": "↑ then ↘",
+ "downThenUpRight": "↓ then ↗",
+ "rightThenUp": "→ then ↑",
+ "rightThenDown": "→ then ↓",
+ "downThenRight": "↓ then →",
+ "downThenLeft": "↓ then ←",
+ "downRightThenUp": "↘ then ↑",
+ "downLeftThenUp": "↙ then ↑",
+ "upLeftThenRight": "↖ then →",
+ "upRightThenLeft": "↗ then ←"
},
"actions": {
"newConversation": "New conversation",
@@ -311,7 +318,16 @@
"renameConversation": "Rename conversation",
"openSessionFolder": "Session files",
"cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "cycleFavoriteAgent": "Favorite agents",
+ "openBallBindings": "Gesture bindings",
+ "cycleRunningSessions": "Running sessions",
+ "cycleRecentSessions": "Recent sessions",
+ "deleteCurrentConversation": "Delete current session",
+ "openImportSessions": "Import sessions",
+ "togglePinConversation": "Pin / unpin session",
+ "focusModeSelector": "Mode selector",
+ "togglePlanFullAccess": "Plan / full access",
+ "openCollaboration": "Collaboration"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "Passed to the CLI as KIRO_API_KEY. Leave empty to use the account you signed in with via kiro-cli login; an API key is only needed where no browser sign-in is possible (servers, Docker).",
"saveConfig": "Save Kiro Config"
},
- "trae": {
- "configManagement": "Configuration",
- "configDescription": "TRAE CLI 2.0 is available to customers on the flagship TRAE Enterprise plan. Codeg runs the traecli you installed, which keeps its sign-in, skills and MCP servers in ~/.trae. Model, mode and reasoning effort are not here: TRAE CLI reports them over ACP, so the composer's own selectors own them per session.",
- "signInTitle": "Sign in",
- "signInHint": "Run this once in a terminal to sign in with your enterprise SSO. Sessions in Codeg reuse that login.",
- "copyCommand": "Copy command",
- "commandCopied": "Command copied",
- "patLabel": "Personal access token (optional)",
- "patHint": "For a machine where browser sign-in is not possible, such as a server or Docker install. Codeg passes it to TRAE CLI as TRAECLI_PERSONAL_ACCESS_TOKEN and signs in with it whenever a session starts. Leave empty to use the login from traecli login.",
- "hostLabel": "Enterprise API URL (optional)",
- "hostHint": "Only if your organization runs TRAE on its own domain. Passed as TRAECLI_HOST; leave empty for TRAE's own service.",
- "saveConfig": "Save TRAE CLI Config"
- },
- "commandCode": {
- "configManagement": "Configuration",
- "configDescription": "Codeg runs the Command Code CLI from the command-code npm package, which keeps its sign-in, skills and MCP servers in ~/.commandcode. Model, mode and reasoning effort are not here: Command Code reports them over ACP, so the composer's own selectors own them per session.",
- "signInTitle": "Sign in",
- "signInHint": "Run this once in a terminal to sign in with your Command Code account. Sessions in Codeg reuse that login.",
- "copyCommand": "Copy command",
- "commandCopied": "Command copied",
- "apiKeyLabel": "API key (optional)",
- "apiKeyHint": "For a machine where browser sign-in is not possible, such as a server or Docker install. Passed to Command Code as COMMAND_CODE_API_KEY, which takes precedence over the login from command-code login. Leave empty to use that login.",
- "saveConfig": "Save Command Code Config"
- },
"deepseek": {
"configManagement": "DeepSeek Harness Configuration",
"configDescription": "The endpoint and key are environment variables deepseek-acp reads at launch. Model and reasoning effort are per-session selectors — pick them in the composer.",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Kiro config saved",
"saveKiroFailed": "Failed to save Kiro config",
- "traeSaved": "TRAE CLI config saved",
- "saveTraeFailed": "Failed to save TRAE CLI config",
- "commandCodeSaved": "Command Code config saved",
- "saveCommandCodeFailed": "Failed to save Command Code config",
"systemAgentAlreadyLatest": "{name} is already up to date ({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "Commits"
},
"noFolderTitle": "No folder open",
- "noFolderHint": "Open a folder to see its contents here",
- "openFullPage": "Open full page",
- "back": "Back",
- "noAutomations": "No automations for this project yet"
+ "noFolderHint": "Open a folder to see its contents here"
},
"windowControls": {
"minimizeWindow": "Minimize window",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "Ask anything...",
- "promptSuggestion": "{suggestion} (Tab to use)",
"removeAttachmentAria": "Remove {name}",
"attachFiles": "Attach files",
"attachLocalUpload": "Upload local file",
@@ -3413,10 +3397,6 @@
"searchModelAria": "Search models",
"modelListLabel": "Models",
"recommendedBadge": "Recommended",
- "recommendedValue": "Recommended: {value}",
- "searchOptions": "Search options...",
- "searchOptionsAria": "Search options",
- "noOptions": "No options found",
"noModels": "No models found",
"cancel": "Cancel",
"send": "Send",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "Message navigation",
+ "collapse": "Collapse message navigation",
"loadingEarlier": "Loading earlier messages…",
"loadEarlier": "Load earlier messages",
+ "collapsedSummary": "Messages {count}",
"fileCount": "{count, plural, one {# file} other {# files}}",
- "subAgentCount": "{count, plural, one {# sub-agent} other {# sub-agents}}",
- "showDiff": "Show the changes to {filePath}",
- "hideDiff": "Hide the changes to {filePath}",
- "openFile": "Open {filePath}",
- "collapse": "Collapse",
- "currentMessage": "Current message",
- "scrollToCurrent": "Scroll to the current message (#{ordinal})"
+ "remove": "Remove",
+ "noDiffDataAvailable": "No diff data available for {filePath}"
},
"replyArtifacts": {
"title": "Files changed",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "Resuming task {task}",
"resumeDelegationNoId": "Resuming a delegated task",
"promptLabel": "Prompt",
- "ackRecorded": "Recorded on the work task",
- "ackNotRecorded": "Not recorded on the work task",
- "ackNotRecordedWithReason": "Not recorded on the work task: {reason}",
"verdict": {
"success": "success",
"needs_review": "needs review",
@@ -4214,18 +4188,6 @@
"stopDeclined": "That task could not be stopped — it may have already finished.",
"stopFailed": "Failed to stop the task: {error}"
},
- "remoteControl": {
- "title": "Remote Control is on",
- "open": "Open in browser",
- "copy": "Copy link",
- "copied": "Copied",
- "qr": "QR code",
- "qrLabel": "QR code for this session's Remote Control link",
- "qrHint": "Scan with your phone to continue this session in the Claude app or on claude.ai/code.",
- "noUrl": "Claude Code returned no link for this session",
- "turnOff": "Turn off",
- "turnOffBusy": "Available once Claude has finished"
- },
"proposedPlan": {
"title": "Proposed plan",
"planning": "Planning…"
@@ -7433,44 +7395,62 @@
"renameConversation": "Rename conversation",
"openSessionFolder": "Session files",
"cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "cycleFavoriteAgent": "Favorite agents",
+ "openBallBindings": "Gesture bindings",
+ "cycleRunningSessions": "Running sessions",
+ "cycleRecentSessions": "Recent sessions",
+ "deleteCurrentConversation": "Delete current session",
+ "openImportSessions": "Import sessions",
+ "togglePinConversation": "Pin / unpin session",
+ "focusModeSelector": "Mode selector",
+ "togglePlanFullAccess": "Plan / full access",
+ "openCollaboration": "Collaboration"
},
"gestures": {
"tap": "Tap",
"doubleTap": "Double tap",
"longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ then ←",
+ "upThenRight": "↑ then →",
+ "upDown": "↑ then ↓",
+ "leftThenRight": "← then →",
+ "rightThenLeft": "→ then ←",
+ "upLeftThenDown": "↖ then ↓",
+ "upRightThenDown": "↗ then ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ then ↑",
+ "upThenDownRight": "↑ then ↘",
+ "downThenUpRight": "↓ then ↗",
+ "rightThenUp": "→ then ↑",
+ "rightThenDown": "→ then ↓",
+ "downThenRight": "↓ then →",
+ "downThenLeft": "↓ then ←",
+ "downRightThenUp": "↘ then ↑",
+ "downLeftThenUp": "↙ then ↑",
+ "upLeftThenRight": "↖ then →",
+ "upRightThenLeft": "↗ then ←"
},
"favoriteAgentsEmpty": "No available agents",
"toasts": {
"renameNeedsSavedSession": "Rename works on a saved session — send a message first.",
"sessionFolderNeedsWorkspace": "Open a workspace folder first.",
- "cycleNeedsMoreAgents": "Only one agent available — nothing to cycle."
- }
+ "cycleNeedsMoreAgents": "Only one agent available — nothing to cycle.",
+ "noOtherRunning": "No other running session to switch to.",
+ "noOtherRecent": "No other recent session to switch to.",
+ "noPlanMode": "This agent has no Plan mode.",
+ "pinToggled": "Pin state updated.",
+ "noRunningSession": "No running session yet.",
+ "noModesAvailable": "This agent does not expose any modes.",
+ "noSwitchTarget": "No mode to switch to (Plan or full-access mode not found)."
+ },
+ "recentSessionDepth": "Recent-session switch depth",
+ "bindingCleared": "Unbound"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json
index 0734ca1a46..fa70d2dc1b 100644
--- a/src/i18n/messages/es.json
+++ b/src/i18n/messages/es.json
@@ -181,6 +181,13 @@
"sectionDescription": "Animaciones de plegado/desplegado, llamadas a herramientas y estado de trabajo en el área de conversación, además del desplazamiento suave. Desactívalas para actualizaciones inmediatas. Los indicadores de carga siguen girando.",
"enable": "Activar las animaciones del chat"
},
+ "messageNav": {
+ "sectionTitle": "Navegador de mensajes",
+ "sectionDescription": "Posición del navegador de mensajes. Abajo a la derecha se convierte en una tarjeta compacta con una fila por mensaje del usuario, sobre el cuadro de entrada.",
+ "positionStart": "Arriba a la izquierda (predeterminado)",
+ "positionBottomEnd": "Abajo a la derecha (compacto)",
+ "hint": "Los paneles de plan y de subagentes siguen arriba a la izquierda."
+ },
"chatWidth": {
"sectionTitle": "Ancho del chat",
"sectionDescription": "Ancho máximo de la columna de conversación y del cuadro de entrada. También puedes arrastrar los bordes del chat para ajustarlo.",
@@ -258,60 +265,69 @@
"panelTitle": "Acciones rápidas"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "Toque",
+ "doubleTap": "Doble toque",
+ "longPress": "Mantener pulsado",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ luego ←",
+ "upThenRight": "↑ luego →",
+ "upDown": "↑ luego ↓",
+ "leftThenRight": "← luego →",
+ "rightThenLeft": "→ luego ←",
+ "upLeftThenDown": "↖ luego ↓",
+ "upRightThenDown": "↗ luego ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ luego ↑",
+ "upThenDownRight": "↑ luego ↘",
+ "downThenUpRight": "↓ luego ↗",
+ "rightThenUp": "→ luego ↑",
+ "rightThenDown": "→ luego ↓",
+ "downThenRight": "↓ luego →",
+ "downThenLeft": "↓ luego ←",
+ "downRightThenUp": "↘ luego ↑",
+ "downLeftThenUp": "↙ luego ↑",
+ "upLeftThenRight": "↖ luego →",
+ "upRightThenLeft": "↗ luego ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
- "openCanvas": "Canvas",
- "openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "newConversation": "Nueva conversación",
+ "toggleSidebar": "Mostrar u ocultar la barra lateral",
+ "toggleSearch": "Buscar",
+ "toggleTerminal": "Mostrar u ocultar la terminal",
+ "nextTab": "Pestaña siguiente",
+ "prevTab": "Pestaña anterior",
+ "reopenClosedTab": "Reabrir pestaña cerrada",
+ "openFolder": "Abrir carpeta",
+ "zoomIn": "Acercar",
+ "zoomOut": "Alejar",
+ "zoomReset": "Restablecer zoom",
+ "stopGenerating": "Detener la generación",
+ "openSettings": "Ajustes",
+ "openTodos": "Tareas",
+ "openTodosNew": "Nueva tarea",
+ "openAutomations": "Automatizaciones",
+ "openCanvas": "Lienzo",
+ "openAgents": "Agentes",
+ "openSystemAdmin": "Administración",
+ "renameConversation": "Renombrar conversación",
+ "openSessionFolder": "Archivos de sesión",
+ "cycleAgent": "Siguiente agente",
+ "cycleFavoriteAgent": "Agentes favoritos",
+ "openBallBindings": "Atajos de gestos",
+ "cycleRunningSessions": "Sesiones en curso",
+ "cycleRecentSessions": "Sesiones recientes",
+ "deleteCurrentConversation": "Eliminar sesión actual",
+ "openImportSessions": "Importar sesiones",
+ "togglePinConversation": "Fijar / desfijar",
+ "focusModeSelector": "Selector de modo",
+ "togglePlanFullAccess": "Plan / acceso total",
+ "openCollaboration": "Colaboración"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "Se pasa a la CLI como KIRO_API_KEY. Déjala vacía para usar la cuenta con la que iniciaste sesión mediante kiro-cli login; solo hace falta donde no se puede iniciar sesión con el navegador (servidores, Docker).",
"saveConfig": "Guardar configuración de Kiro"
},
- "trae": {
- "configManagement": "Configuración",
- "configDescription": "TRAE CLI 2.0 solo está disponible para clientes del plan insignia de TRAE Enterprise. Codeg ejecuta el traecli que instalaste, que guarda su inicio de sesión, sus habilidades y sus servidores MCP en ~/.trae. El modelo, el modo y el esfuerzo de razonamiento no están aquí: TRAE CLI los informa por ACP, así que los selectores del compositor los gestionan en cada sesión.",
- "signInTitle": "Iniciar sesión",
- "signInHint": "Ejecuta esto una vez en una terminal para iniciar sesión con el SSO de tu empresa. Las sesiones de Codeg reutilizan ese inicio de sesión.",
- "copyCommand": "Copiar comando",
- "commandCopied": "Comando copiado",
- "patLabel": "Token de acceso personal (opcional)",
- "patHint": "Para una máquina donde no se puede iniciar sesión con el navegador, como un servidor o una instalación de Docker. Codeg lo pasa a TRAE CLI como TRAECLI_PERSONAL_ACCESS_TOKEN e inicia sesión con él cada vez que empieza una sesión. Déjalo vacío para usar el inicio de sesión de traecli login.",
- "hostLabel": "URL de la API empresarial (opcional)",
- "hostHint": "Solo si tu organización ejecuta TRAE en su propio dominio. Se pasa como TRAECLI_HOST; déjala vacía para usar el servicio de TRAE.",
- "saveConfig": "Guardar configuración de TRAE CLI"
- },
- "commandCode": {
- "configManagement": "Configuración",
- "configDescription": "Codeg ejecuta la CLI de Command Code del paquete npm command-code, que guarda su inicio de sesión, sus habilidades y sus servidores MCP en ~/.commandcode. El modelo, el modo y el esfuerzo de razonamiento no están aquí: Command Code los informa por ACP, así que los selectores del compositor los gestionan en cada sesión.",
- "signInTitle": "Iniciar sesión",
- "signInHint": "Ejecuta esto una vez en una terminal para iniciar sesión con tu cuenta de Command Code. Las sesiones de Codeg reutilizan ese inicio de sesión.",
- "copyCommand": "Copiar comando",
- "commandCopied": "Comando copiado",
- "apiKeyLabel": "Clave de API (opcional)",
- "apiKeyHint": "Para una máquina donde no se puede iniciar sesión con el navegador, como un servidor o una instalación de Docker. Se pasa a Command Code como COMMAND_CODE_API_KEY, que tiene prioridad sobre el inicio de sesión de command-code login. Déjala vacía para usar ese inicio de sesión.",
- "saveConfig": "Guardar configuración de Command Code"
- },
"deepseek": {
"configManagement": "Configuración de DeepSeek Harness",
"configDescription": "El endpoint y la clave son variables de entorno que deepseek-acp lee al arrancar. El modelo y el esfuerzo de razonamiento son selectores por sesión: se eligen en el campo de mensaje.",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Configuración de Kiro guardada",
"saveKiroFailed": "No se pudo guardar la configuración de Kiro",
- "traeSaved": "Configuración de TRAE CLI guardada",
- "saveTraeFailed": "No se pudo guardar la configuración de TRAE CLI",
- "commandCodeSaved": "Configuración de Command Code guardada",
- "saveCommandCodeFailed": "No se pudo guardar la configuración de Command Code",
"systemAgentAlreadyLatest": "{name} ya está al día ({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "Confirmaciones"
},
"noFolderTitle": "No hay carpeta abierta",
- "noFolderHint": "Abre una carpeta para ver su contenido aquí",
- "openFullPage": "Abrir en página completa",
- "back": "Atrás",
- "noAutomations": "Este proyecto aún no tiene automatizaciones"
+ "noFolderHint": "Abre una carpeta para ver su contenido aquí"
},
"windowControls": {
"minimizeWindow": "Minimizar ventana",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "Pregunta lo que sea...",
- "promptSuggestion": "{suggestion} (Tab para usarla)",
"removeAttachmentAria": "Quitar {name}",
"attachFiles": "Adjuntar archivos",
"addActions": "Añadir",
@@ -3411,10 +3395,6 @@
"searchModelAria": "Buscar modelos",
"modelListLabel": "Modelos",
"recommendedBadge": "Recomendado",
- "recommendedValue": "Recomendado: {value}",
- "searchOptions": "Buscar opciones...",
- "searchOptionsAria": "Buscar opciones",
- "noOptions": "No se encontraron opciones",
"noModels": "No se encontraron modelos",
"cancel": "Cancelar",
"send": "Enviar",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "Navegación de mensajes",
+ "collapse": "Contraer navegación de mensajes",
"loadingEarlier": "Cargando mensajes anteriores…",
"loadEarlier": "Cargar mensajes anteriores",
+ "collapsedSummary": "Mensajes {count}",
"fileCount": "{count, plural, one {# archivo} other {# archivos}}",
- "subAgentCount": "{count, plural, one {# subagente} other {# subagentes}}",
- "showDiff": "Mostrar los cambios de {filePath}",
- "hideDiff": "Ocultar los cambios de {filePath}",
- "openFile": "Abrir {filePath}",
- "collapse": "Contraer",
- "currentMessage": "Mensaje actual",
- "scrollToCurrent": "Desplazarse al mensaje actual (#{ordinal})"
+ "remove": "Quitar",
+ "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}"
},
"replyArtifacts": {
"title": "Archivos modificados",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "Reanudando la tarea {task}",
"resumeDelegationNoId": "Reanudando una tarea delegada",
"promptLabel": "Instrucción",
- "ackRecorded": "Registrado en la tarea de trabajo",
- "ackNotRecorded": "No registrado en la tarea de trabajo",
- "ackNotRecordedWithReason": "No registrado en la tarea de trabajo: {reason}",
"verdict": {
"success": "correcta",
"needs_review": "requiere revisión",
@@ -4214,18 +4188,6 @@
"stopDeclined": "No se pudo detener esa tarea; puede que ya haya terminado.",
"stopFailed": "No se pudo detener la tarea: {error}"
},
- "remoteControl": {
- "title": "Control remoto activado",
- "open": "Abrir en el navegador",
- "copy": "Copiar enlace",
- "copied": "Copiado",
- "qr": "Código QR",
- "qrLabel": "Código QR del enlace de control remoto de esta sesión",
- "qrHint": "Escanéalo con el teléfono para continuar esta sesión en la app de Claude o en claude.ai/code.",
- "noUrl": "Claude Code no devolvió ningún enlace para esta sesión",
- "turnOff": "Desactivar",
- "turnOffBusy": "Disponible cuando Claude termine"
- },
"proposedPlan": {
"title": "Plan propuesto",
"planning": "Planificando…"
@@ -7433,44 +7395,62 @@
"renameConversation": "Renombrar conversación",
"openSessionFolder": "Archivos de sesión",
"cycleAgent": "Siguiente agente",
- "cycleFavoriteAgent": "Agentes favoritos"
+ "cycleFavoriteAgent": "Agentes favoritos",
+ "openBallBindings": "Atajos de gestos",
+ "cycleRunningSessions": "Sesiones en curso",
+ "cycleRecentSessions": "Sesiones recientes",
+ "deleteCurrentConversation": "Eliminar sesión actual",
+ "openImportSessions": "Importar sesiones",
+ "togglePinConversation": "Fijar / desfijar",
+ "focusModeSelector": "Selector de modo",
+ "togglePlanFullAccess": "Plan / acceso total",
+ "openCollaboration": "Colaboración"
},
"gestures": {
"tap": "Toque",
"doubleTap": "Doble toque",
- "longPress": "Pulsación larga",
- "left": "Deslizar a la izquierda",
- "right": "Deslizar a la derecha",
- "up": "Deslizar hacia arriba",
- "upLeft": "Arriba a la izquierda",
- "upRight": "Arriba a la derecha",
- "upThenLeft": "Arriba y luego a la izquierda",
- "upThenRight": "Arriba y luego a la derecha",
- "upDown": "Arriba y luego abajo",
- "leftThenRight": "Izquierda y luego derecha",
- "rightThenLeft": "Derecha y luego izquierda",
- "upLeftThenDown": "Arriba a la izquierda y luego abajo",
- "upRightThenDown": "Arriba a la derecha y luego abajo",
- "down": "Deslizar abajo",
- "downLeft": "Abajo-izq.",
- "downRight": "Abajo-der.",
- "downUp": "Abajo, luego arriba",
- "upThenDownRight": "Arriba, luego abajo-der.",
- "downThenUpRight": "Abajo, luego arriba-der.",
- "rightThenUp": "Derecha, luego arriba",
- "rightThenDown": "Derecha, luego abajo",
- "downThenRight": "Abajo, luego derecha",
- "downThenLeft": "Abajo, luego izquierda",
- "downRightThenUp": "Abajo-der., luego arriba",
- "downLeftThenUp": "Abajo-izq., luego arriba",
- "upLeftThenRight": "Arriba-izq., luego derecha",
- "upRightThenLeft": "Arriba-der., luego izquierda"
+ "longPress": "Mantener pulsado",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ luego ←",
+ "upThenRight": "↑ luego →",
+ "upDown": "↑ luego ↓",
+ "leftThenRight": "← luego →",
+ "rightThenLeft": "→ luego ←",
+ "upLeftThenDown": "↖ luego ↓",
+ "upRightThenDown": "↗ luego ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ luego ↑",
+ "upThenDownRight": "↑ luego ↘",
+ "downThenUpRight": "↓ luego ↗",
+ "rightThenUp": "→ luego ↑",
+ "rightThenDown": "→ luego ↓",
+ "downThenRight": "↓ luego →",
+ "downThenLeft": "↓ luego ←",
+ "downRightThenUp": "↘ luego ↑",
+ "downLeftThenUp": "↙ luego ↑",
+ "upLeftThenRight": "↖ luego →",
+ "upRightThenLeft": "↗ luego ←"
},
"favoriteAgentsEmpty": "No hay agentes disponibles",
"toasts": {
"renameNeedsSavedSession": "Renombrar solo funciona en sesiones guardadas: envía un mensaje primero.",
"sessionFolderNeedsWorkspace": "Abre antes una carpeta de espacio de trabajo.",
- "cycleNeedsMoreAgents": "Solo hay un agente disponible: nada que alternar."
- }
+ "cycleNeedsMoreAgents": "Solo hay un agente disponible: nada que alternar.",
+ "noOtherRunning": "No hay otra sesión en curso.",
+ "noOtherRecent": "No hay otra sesión reciente.",
+ "noPlanMode": "Este agente no tiene modo Plan.",
+ "pinToggled": "Estado de fijado actualizado.",
+ "noRunningSession": "Aún no hay sesión en curso.",
+ "noModesAvailable": "Este agente no expone ningún modo.",
+ "noSwitchTarget": "No hay modo al que cambiar (no se encontró modo Plan ni de acceso completo)."
+ },
+ "recentSessionDepth": "Profundidad de sesiones recientes",
+ "bindingCleared": "Sin asignar"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json
index da1c5539bc..7a4b3a2930 100644
--- a/src/i18n/messages/fr.json
+++ b/src/i18n/messages/fr.json
@@ -181,6 +181,13 @@
"sectionDescription": "Animations de pliage/dépliage, d'appels d'outils et d'état de travail dans la zone de conversation, ainsi que le défilement fluide. Désactivez-les pour des mises à jour instantanées. Les indicateurs de chargement continuent de tourner.",
"enable": "Activer les animations du chat"
},
+ "messageNav": {
+ "sectionTitle": "Navigateur de messages",
+ "sectionDescription": "Position du navigateur de messages. En bas à droite, il devient une carte compacte avec une ligne par message utilisateur, au-dessus de la zone de saisie.",
+ "positionStart": "En haut à gauche (par défaut)",
+ "positionBottomEnd": "En bas à droite (compact)",
+ "hint": "Les panneaux de plan et de sous-agents restent en haut à gauche."
+ },
"chatWidth": {
"sectionTitle": "Largeur du chat",
"sectionDescription": "Largeur maximale de la colonne de conversation et de la zone de saisie. Vous pouvez aussi faire glisser les bords du chat pour l'ajuster.",
@@ -258,60 +265,69 @@
"panelTitle": "Actions rapides"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "Touche",
+ "doubleTap": "Double touche",
+ "longPress": "Appui long",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ puis ←",
+ "upThenRight": "↑ puis →",
+ "upDown": "↑ puis ↓",
+ "leftThenRight": "← puis →",
+ "rightThenLeft": "→ puis ←",
+ "upLeftThenDown": "↖ puis ↓",
+ "upRightThenDown": "↗ puis ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ puis ↑",
+ "upThenDownRight": "↑ puis ↘",
+ "downThenUpRight": "↓ puis ↗",
+ "rightThenUp": "→ puis ↑",
+ "rightThenDown": "→ puis ↓",
+ "downThenRight": "↓ puis →",
+ "downThenLeft": "↓ puis ←",
+ "downRightThenUp": "↘ puis ↑",
+ "downLeftThenUp": "↙ puis ↑",
+ "upLeftThenRight": "↖ puis →",
+ "upRightThenLeft": "↗ puis ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
+ "newConversation": "Nouvelle conversation",
+ "toggleSidebar": "Afficher ou masquer la barre latérale",
+ "toggleSearch": "Rechercher",
+ "toggleTerminal": "Afficher ou masquer le terminal",
+ "nextTab": "Onglet suivant",
+ "prevTab": "Onglet précédent",
+ "reopenClosedTab": "Rouvrir l’onglet fermé",
+ "openFolder": "Ouvrir un dossier",
+ "zoomIn": "Zoom avant",
+ "zoomOut": "Zoom arrière",
+ "zoomReset": "Réinitialiser le zoom",
+ "stopGenerating": "Arrêter la génération",
+ "openSettings": "Paramètres",
+ "openTodos": "Tâches",
+ "openTodosNew": "Nouvelle tâche",
+ "openAutomations": "Automatisations",
"openCanvas": "Canvas",
"openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "openSystemAdmin": "Administration",
+ "renameConversation": "Renommer la conversation",
+ "openSessionFolder": "Fichiers de session",
+ "cycleAgent": "Agent suivant",
+ "cycleFavoriteAgent": "Agents favoris",
+ "openBallBindings": "Assignation des gestes",
+ "cycleRunningSessions": "Sessions en cours",
+ "cycleRecentSessions": "Sessions récentes",
+ "deleteCurrentConversation": "Supprimer la session",
+ "openImportSessions": "Importer des sessions",
+ "togglePinConversation": "Épingler / désépingler",
+ "focusModeSelector": "Sélecteur de mode",
+ "togglePlanFullAccess": "Plan / accès complet",
+ "openCollaboration": "Collaboration"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "Transmise à la CLI en tant que KIRO_API_KEY. Laissez vide pour utiliser le compte connecté via kiro-cli login ; nécessaire seulement là où la connexion par navigateur est impossible (serveurs, Docker).",
"saveConfig": "Enregistrer la configuration Kiro"
},
- "trae": {
- "configManagement": "Configuration",
- "configDescription": "TRAE CLI 2.0 est réservé aux clients de l'offre phare de TRAE Enterprise. Codeg lance le traecli que vous avez installé, qui conserve sa connexion, ses compétences et ses serveurs MCP dans ~/.trae. Le modèle, le mode et l'effort de raisonnement ne sont pas ici : TRAE CLI les communique via ACP, donc les sélecteurs du compositeur les gèrent pour chaque session.",
- "signInTitle": "Connexion",
- "signInHint": "Exécutez cette commande une fois dans un terminal pour vous connecter avec le SSO de votre entreprise. Les sessions de Codeg réutilisent cette connexion.",
- "copyCommand": "Copier la commande",
- "commandCopied": "Commande copiée",
- "patLabel": "Jeton d'accès personnel (facultatif)",
- "patHint": "Pour une machine où la connexion par navigateur est impossible, comme un serveur ou une installation Docker. Codeg le transmet à TRAE CLI en tant que TRAECLI_PERSONAL_ACCESS_TOKEN et se connecte avec lui au démarrage de chaque session. Laissez vide pour utiliser la connexion de traecli login.",
- "hostLabel": "URL de l'API d'entreprise (facultative)",
- "hostHint": "Uniquement si votre organisation exploite TRAE sur son propre domaine. Transmise en tant que TRAECLI_HOST ; laissez vide pour le service de TRAE.",
- "saveConfig": "Enregistrer la configuration TRAE CLI"
- },
- "commandCode": {
- "configManagement": "Configuration",
- "configDescription": "Codeg lance la CLI Command Code du paquet npm command-code, qui conserve sa connexion, ses compétences et ses serveurs MCP dans ~/.commandcode. Le modèle, le mode et l'effort de raisonnement ne sont pas ici : Command Code les communique via ACP, donc les sélecteurs du compositeur les gèrent pour chaque session.",
- "signInTitle": "Connexion",
- "signInHint": "Exécutez cette commande une fois dans un terminal pour vous connecter avec votre compte Command Code. Les sessions de Codeg réutilisent cette connexion.",
- "copyCommand": "Copier la commande",
- "commandCopied": "Commande copiée",
- "apiKeyLabel": "Clé d'API (facultative)",
- "apiKeyHint": "Pour une machine où la connexion par navigateur est impossible, comme un serveur ou une installation Docker. Transmise à Command Code en tant que COMMAND_CODE_API_KEY, prioritaire sur la connexion de command-code login. Laissez vide pour utiliser cette connexion.",
- "saveConfig": "Enregistrer la configuration Command Code"
- },
"deepseek": {
"configManagement": "Configuration de DeepSeek Harness",
"configDescription": "Le point de terminaison et la clé sont des variables d'environnement que deepseek-acp lit au démarrage. Le modèle et le niveau de raisonnement sont des sélecteurs par session : ils se choisissent dans le champ de saisie.",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Configuration Kiro enregistrée",
"saveKiroFailed": "Impossible d'enregistrer la configuration Kiro",
- "traeSaved": "Configuration TRAE CLI enregistrée",
- "saveTraeFailed": "Impossible d'enregistrer la configuration TRAE CLI",
- "commandCodeSaved": "Configuration Command Code enregistrée",
- "saveCommandCodeFailed": "Impossible d'enregistrer la configuration Command Code",
"systemAgentAlreadyLatest": "{name} est déjà à jour ({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "Validations"
},
"noFolderTitle": "Aucun dossier ouvert",
- "noFolderHint": "Ouvrez un dossier pour voir son contenu ici",
- "openFullPage": "Ouvrir en pleine page",
- "back": "Retour",
- "noAutomations": "Aucune automatisation pour ce projet pour l’instant"
+ "noFolderHint": "Ouvrez un dossier pour voir son contenu ici"
},
"windowControls": {
"minimizeWindow": "Minimiser la fenêtre",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "Posez n'importe quelle question...",
- "promptSuggestion": "{suggestion} (Tab pour l’utiliser)",
"removeAttachmentAria": "Retirer {name}",
"attachFiles": "Joindre des fichiers",
"addActions": "Ajouter",
@@ -3411,10 +3395,6 @@
"searchModelAria": "Rechercher des modèles",
"modelListLabel": "Modèles",
"recommendedBadge": "Recommandé",
- "recommendedValue": "Recommandé : {value}",
- "searchOptions": "Rechercher des options...",
- "searchOptionsAria": "Rechercher des options",
- "noOptions": "Aucune option trouvée",
"noModels": "Aucun modèle trouvé",
"cancel": "Annuler",
"send": "Envoyer",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "Navigation des messages",
+ "collapse": "Réduire la navigation des messages",
"loadingEarlier": "Chargement des messages précédents…",
"loadEarlier": "Charger les messages précédents",
+ "collapsedSummary": "Messages {count}",
"fileCount": "{count, plural, one {# fichier} other {# fichiers}}",
- "subAgentCount": "{count, plural, one {# sous-agent} other {# sous-agents}}",
- "showDiff": "Afficher les modifications de {filePath}",
- "hideDiff": "Masquer les modifications de {filePath}",
- "openFile": "Ouvrir {filePath}",
- "collapse": "Réduire",
- "currentMessage": "Message actuel",
- "scrollToCurrent": "Faire défiler jusqu’au message actuel (#{ordinal})"
+ "remove": "Retirer",
+ "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}"
},
"replyArtifacts": {
"title": "Fichiers modifiés",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "Reprise de la tâche {task}",
"resumeDelegationNoId": "Reprise d'une tâche déléguée",
"promptLabel": "Instruction",
- "ackRecorded": "Enregistré dans la tâche",
- "ackNotRecorded": "Non enregistré dans la tâche",
- "ackNotRecordedWithReason": "Non enregistré dans la tâche : {reason}",
"verdict": {
"success": "réussie",
"needs_review": "à relire",
@@ -4214,18 +4188,6 @@
"stopDeclined": "Impossible d'arrêter cette tâche : elle est peut-être déjà terminée.",
"stopFailed": "Échec de l'arrêt de la tâche : {error}"
},
- "remoteControl": {
- "title": "Contrôle à distance activé",
- "open": "Ouvrir dans le navigateur",
- "copy": "Copier le lien",
- "copied": "Copié",
- "qr": "Code QR",
- "qrLabel": "Code QR du lien de contrôle à distance de cette session",
- "qrHint": "Scannez-le avec votre téléphone pour poursuivre cette session dans l'app Claude ou sur claude.ai/code.",
- "noUrl": "Claude Code n'a renvoyé aucun lien pour cette session",
- "turnOff": "Désactiver",
- "turnOffBusy": "Disponible une fois que Claude a terminé"
- },
"proposedPlan": {
"title": "Plan proposé",
"planning": "Planification…"
@@ -7433,44 +7395,62 @@
"renameConversation": "Renommer la conversation",
"openSessionFolder": "Fichiers de session",
"cycleAgent": "Agent suivant",
- "cycleFavoriteAgent": "Agents favoris"
+ "cycleFavoriteAgent": "Agents favoris",
+ "openBallBindings": "Assignation des gestes",
+ "cycleRunningSessions": "Sessions en cours",
+ "cycleRecentSessions": "Sessions récentes",
+ "deleteCurrentConversation": "Supprimer la session",
+ "openImportSessions": "Importer des sessions",
+ "togglePinConversation": "Épingler / désépingler",
+ "focusModeSelector": "Sélecteur de mode",
+ "togglePlanFullAccess": "Plan / accès complet",
+ "openCollaboration": "Collaboration"
},
"gestures": {
- "tap": "Appui",
- "doubleTap": "Double appui",
+ "tap": "Touche",
+ "doubleTap": "Double touche",
"longPress": "Appui long",
- "left": "Balayage à gauche",
- "right": "Balayage à droite",
- "up": "Balayage vers le haut",
- "upLeft": "Haut-gauche",
- "upRight": "Haut-droite",
- "upThenLeft": "Haut, puis gauche",
- "upThenRight": "Haut, puis droite",
- "upDown": "Haut, puis bas",
- "leftThenRight": "Gauche, puis droite",
- "rightThenLeft": "Droite, puis gauche",
- "upLeftThenDown": "Haut-gauche, puis bas",
- "upRightThenDown": "Haut-droite, puis bas",
- "down": "Balayer vers le bas",
- "downLeft": "Bas-gauche",
- "downRight": "Bas-droite",
- "downUp": "Bas, puis haut",
- "upThenDownRight": "Haut, puis bas-dr.",
- "downThenUpRight": "Bas, puis haut-dr.",
- "rightThenUp": "Droite, puis haut",
- "rightThenDown": "Droite, puis bas",
- "downThenRight": "Bas, puis droite",
- "downThenLeft": "Bas, puis gauche",
- "downRightThenUp": "Bas-dr., puis haut",
- "downLeftThenUp": "Bas-g., puis haut",
- "upLeftThenRight": "Haut-g., puis droite",
- "upRightThenLeft": "Haut-dr., puis gauche"
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ puis ←",
+ "upThenRight": "↑ puis →",
+ "upDown": "↑ puis ↓",
+ "leftThenRight": "← puis →",
+ "rightThenLeft": "→ puis ←",
+ "upLeftThenDown": "↖ puis ↓",
+ "upRightThenDown": "↗ puis ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ puis ↑",
+ "upThenDownRight": "↑ puis ↘",
+ "downThenUpRight": "↓ puis ↗",
+ "rightThenUp": "→ puis ↑",
+ "rightThenDown": "→ puis ↓",
+ "downThenRight": "↓ puis →",
+ "downThenLeft": "↓ puis ←",
+ "downRightThenUp": "↘ puis ↑",
+ "downLeftThenUp": "↙ puis ↑",
+ "upLeftThenRight": "↖ puis →",
+ "upRightThenLeft": "↗ puis ←"
},
"favoriteAgentsEmpty": "Aucun agent disponible",
"toasts": {
"renameNeedsSavedSession": "Renommer ne s'applique qu'aux sessions enregistrées — envoyez d'abord un message.",
"sessionFolderNeedsWorkspace": "Ouvrez d'abord un dossier d'espace de travail.",
- "cycleNeedsMoreAgents": "Un seul agent disponible — rien à parcourir."
- }
+ "cycleNeedsMoreAgents": "Un seul agent disponible — rien à parcourir.",
+ "noOtherRunning": "Aucune autre session en cours.",
+ "noOtherRecent": "Aucune autre session récente.",
+ "noPlanMode": "Cet agent n'a pas de mode Plan.",
+ "pinToggled": "État d'épinglage mis à jour.",
+ "noRunningSession": "Aucune session en cours.",
+ "noModesAvailable": "Cet agent n'expose aucun mode.",
+ "noSwitchTarget": "Aucun mode vers lequel basculer (mode Plan ou accès complet introuvable)."
+ },
+ "recentSessionDepth": "Profondeur des sessions récentes",
+ "bindingCleared": "Non attribué"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json
index c00a6584c7..d7e7556308 100644
--- a/src/i18n/messages/ja.json
+++ b/src/i18n/messages/ja.json
@@ -181,6 +181,13 @@
"sectionDescription": "会話エリア内の折りたたみ/展開、ツール呼び出し、作業状態などのアニメーションとスムーズスクロールを制御します。オフにすると即時に更新されます。スピナーは回転し続けます。",
"enable": "チャットのアニメーションを有効にする"
},
+ "messageNav": {
+ "sectionTitle": "メッセージナビ",
+ "sectionDescription": "会話のメッセージナビの位置。右下を選ぶと、ユーザーの発話ごとに 1 行のコンパクトなカードになり、入力欄の上に表示されます。",
+ "positionStart": "左上(既定)",
+ "positionBottomEnd": "右下(コンパクト)",
+ "hint": "プランパネルとサブエージェントパネルは常に左上に残ります。"
+ },
"chatWidth": {
"sectionTitle": "チャット幅",
"sectionDescription": "会話列と入力欄の最大幅です。チャット領域の左右の端をドラッグして調整することもできます。",
@@ -258,60 +265,69 @@
"panelTitle": "クイック操作"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "タップ",
+ "doubleTap": "ダブルタップ",
+ "longPress": "長押し",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ その後 ←",
+ "upThenRight": "↑ その後 →",
+ "upDown": "↑ その後 ↓",
+ "leftThenRight": "← その後 →",
+ "rightThenLeft": "→ その後 ←",
+ "upLeftThenDown": "↖ その後 ↓",
+ "upRightThenDown": "↗ その後 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ その後 ↑",
+ "upThenDownRight": "↑ その後 ↘",
+ "downThenUpRight": "↓ その後 ↗",
+ "rightThenUp": "→ その後 ↑",
+ "rightThenDown": "→ その後 ↓",
+ "downThenRight": "↓ その後 →",
+ "downThenLeft": "↓ その後 ←",
+ "downRightThenUp": "↘ その後 ↑",
+ "downLeftThenUp": "↙ その後 ↑",
+ "upLeftThenRight": "↖ その後 →",
+ "upRightThenLeft": "↗ その後 ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
- "openCanvas": "Canvas",
- "openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "newConversation": "新しい会話",
+ "toggleSidebar": "サイドバーの切り替え",
+ "toggleSearch": "検索",
+ "toggleTerminal": "ターミナルの切り替え",
+ "nextTab": "次のタブ",
+ "prevTab": "前のタブ",
+ "reopenClosedTab": "閉じたタブを開き直す",
+ "openFolder": "フォルダーを開く",
+ "zoomIn": "拡大",
+ "zoomOut": "縮小",
+ "zoomReset": "ズームをリセット",
+ "stopGenerating": "生成を停止",
+ "openSettings": "設定",
+ "openTodos": "ToDo",
+ "openTodosNew": "ToDo作成",
+ "openAutomations": "オートメーション",
+ "openCanvas": "キャンバス",
+ "openAgents": "エージェント",
+ "openSystemAdmin": "システム管理",
+ "renameConversation": "会話名を変更",
+ "openSessionFolder": "セッションファイル",
+ "cycleAgent": "次のエージェント",
+ "cycleFavoriteAgent": "お気に入りエージェント",
+ "openBallBindings": "ジェスチャー設定",
+ "cycleRunningSessions": "実行中のセッション",
+ "cycleRecentSessions": "最近のセッション",
+ "deleteCurrentConversation": "現在のセッションを削除",
+ "openImportSessions": "セッションをインポート",
+ "togglePinConversation": "ピン留め切り替え",
+ "focusModeSelector": "モード選択",
+ "togglePlanFullAccess": "Plan/フルアクセス切替",
+ "openCollaboration": "コラボレーション"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "KIRO_API_KEY として CLI に渡されます。空欄なら kiro-cli login でサインインしたアカウントを使います。ブラウザでサインインできない環境(サーバー、Docker)でのみ必要です。",
"saveConfig": "Kiro 設定を保存"
},
- "trae": {
- "configManagement": "設定管理",
- "configDescription": "TRAE CLI 2.0 は TRAE エンタープライズ版のフラッグシッププランのお客様のみ利用できます。Codeg はインストール済みの traecli を実行し、サインイン情報・スキル・MCP サーバーは ~/.trae に保存されます。モデル、モード、推論レベルはここにはありません。TRAE CLI が ACP で報告するため、入力欄のセレクターがセッションごとに管理します。",
- "signInTitle": "サインイン",
- "signInHint": "ターミナルでこのコマンドを一度実行し、エンタープライズ SSO でサインインしてください。Codeg のセッションはそのサインインを再利用します。",
- "copyCommand": "コマンドをコピー",
- "commandCopied": "コマンドをコピーしました",
- "patLabel": "個人アクセストークン(任意)",
- "patHint": "サーバーや Docker など、ブラウザでサインインできないマシン向けです。Codeg は TRAECLI_PERSONAL_ACCESS_TOKEN として TRAE CLI に渡し、セッション開始時にこのトークンでサインインします。空欄なら traecli login のサインインを使います。",
- "hostLabel": "エンタープライズ API URL(任意)",
- "hostHint": "組織が独自ドメインで TRAE を運用している場合のみ入力します。TRAECLI_HOST として渡されます。空欄なら TRAE の公式サービスを使います。",
- "saveConfig": "TRAE CLI 設定を保存"
- },
- "commandCode": {
- "configManagement": "設定管理",
- "configDescription": "Codeg は command-code npm パッケージの Command Code CLI を実行し、サインイン情報・スキル・MCP サーバーは ~/.commandcode に保存されます。モデル、モード、推論レベルはここにはありません。Command Code が ACP で報告するため、入力欄のセレクターがセッションごとに管理します。",
- "signInTitle": "サインイン",
- "signInHint": "ターミナルでこのコマンドを一度実行し、Command Code アカウントでサインインしてください。Codeg のセッションはそのサインインを再利用します。",
- "copyCommand": "コマンドをコピー",
- "commandCopied": "コマンドをコピーしました",
- "apiKeyLabel": "API キー(任意)",
- "apiKeyHint": "サーバーや Docker など、ブラウザでサインインできないマシン向けです。COMMAND_CODE_API_KEY として Command Code に渡され、command-code login のサインインより優先されます。空欄ならそのサインインを使います。",
- "saveConfig": "Command Code 設定を保存"
- },
"deepseek": {
"configManagement": "DeepSeek Harness の設定",
"configDescription": "エンドポイントと API キーは deepseek-acp が起動時に読み込む環境変数です。モデルと推論レベルはセッションごとのセレクターなので、入力欄で切り替えます。",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Kiro 設定を保存しました",
"saveKiroFailed": "Kiro 設定の保存に失敗しました",
- "traeSaved": "TRAE CLI 設定を保存しました",
- "saveTraeFailed": "TRAE CLI 設定の保存に失敗しました",
- "commandCodeSaved": "Command Code 設定を保存しました",
- "saveCommandCodeFailed": "Command Code 設定の保存に失敗しました",
"systemAgentAlreadyLatest": "{name} は最新です({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "コミット"
},
"noFolderTitle": "開いているフォルダがありません",
- "noFolderHint": "フォルダを開くとここに表示されます",
- "openFullPage": "フルページで開く",
- "back": "戻る",
- "noAutomations": "このプロジェクトにはまだオートメーションがありません"
+ "noFolderHint": "フォルダを開くとここに表示されます"
},
"windowControls": {
"minimizeWindow": "ウィンドウを最小化",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "何でも質問してください...",
- "promptSuggestion": "{suggestion}(Tab で入力)",
"removeAttachmentAria": "{name} を削除",
"attachFiles": "ファイルを添付",
"addActions": "追加",
@@ -3411,10 +3395,6 @@
"searchModelAria": "モデルを検索",
"modelListLabel": "モデル",
"recommendedBadge": "推奨",
- "recommendedValue": "推奨: {value}",
- "searchOptions": "オプションを検索...",
- "searchOptionsAria": "オプションを検索",
- "noOptions": "オプションが見つかりません",
"noModels": "モデルが見つかりません",
"cancel": "キャンセル",
"send": "送信",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "メッセージナビ",
+ "collapse": "メッセージナビを閉じる",
"loadingEarlier": "以前のメッセージを読み込み中…",
"loadEarlier": "以前のメッセージを読み込む",
+ "collapsedSummary": "メッセージ {count}",
"fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}",
- "subAgentCount": "{count, plural, one {# 個のサブエージェント} other {# 個のサブエージェント}}",
- "showDiff": "{filePath} の変更を表示",
- "hideDiff": "{filePath} の変更を隠す",
- "openFile": "{filePath} を開く",
- "collapse": "折りたたむ",
- "currentMessage": "現在のメッセージ",
- "scrollToCurrent": "現在のメッセージ(#{ordinal})へスクロール"
+ "remove": "削除",
+ "noDiffDataAvailable": "{filePath} の差分データがありません"
},
"replyArtifacts": {
"title": "変更されたファイル",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "タスク {task} を再開中",
"resumeDelegationNoId": "委任タスクを再開中",
"promptLabel": "プロンプト",
- "ackRecorded": "作業タスクに記録しました",
- "ackNotRecorded": "作業タスクに記録されていません",
- "ackNotRecordedWithReason": "作業タスクに記録されていません: {reason}",
"verdict": {
"success": "成功",
"needs_review": "要確認",
@@ -4214,18 +4188,6 @@
"stopDeclined": "このタスクは停止できませんでした。すでに終了している可能性があります。",
"stopFailed": "タスクの停止に失敗しました: {error}"
},
- "remoteControl": {
- "title": "リモートコントロール有効",
- "open": "ブラウザで開く",
- "copy": "リンクをコピー",
- "copied": "コピーしました",
- "qr": "QR コード",
- "qrLabel": "このセッションのリモートコントロール用リンクの QR コード",
- "qrHint": "スマートフォンでスキャンすると、Claude アプリまたは claude.ai/code でこのセッションを続けられます。",
- "noUrl": "Claude Code はこのセッションのリンクを返しませんでした",
- "turnOff": "オフにする",
- "turnOffBusy": "Claude の作業が終わると使えます"
- },
"proposedPlan": {
"title": "提案された計画",
"planning": "計画中…"
@@ -7433,44 +7395,62 @@
"renameConversation": "会話名を変更",
"openSessionFolder": "セッションファイル",
"cycleAgent": "次のエージェント",
- "cycleFavoriteAgent": "お気に入りエージェント"
+ "cycleFavoriteAgent": "お気に入りエージェント",
+ "openBallBindings": "ジェスチャー設定",
+ "cycleRunningSessions": "実行中のセッション",
+ "cycleRecentSessions": "最近のセッション",
+ "deleteCurrentConversation": "現在のセッションを削除",
+ "openImportSessions": "セッションをインポート",
+ "togglePinConversation": "ピン留め切り替え",
+ "focusModeSelector": "モード選択",
+ "togglePlanFullAccess": "Plan/フルアクセス切替",
+ "openCollaboration": "コラボレーション"
},
"gestures": {
"tap": "タップ",
"doubleTap": "ダブルタップ",
"longPress": "長押し",
- "left": "左スワイプ",
- "right": "右スワイプ",
- "up": "上スワイプ",
- "upLeft": "左上スワイプ",
- "upRight": "右上スワイプ",
- "upThenLeft": "上→左",
- "upThenRight": "上→右",
- "upDown": "上→下",
- "leftThenRight": "左→右",
- "rightThenLeft": "右→左",
- "upLeftThenDown": "左上→下",
- "upRightThenDown": "右上→下",
- "down": "下スワイプ",
- "downLeft": "左下",
- "downRight": "右下",
- "downUp": "下から上",
- "upThenDownRight": "上から右下",
- "downThenUpRight": "下から右上",
- "rightThenUp": "右から上",
- "rightThenDown": "右から下",
- "downThenRight": "下から右",
- "downThenLeft": "下から左",
- "downRightThenUp": "右下から上",
- "downLeftThenUp": "左下から上",
- "upLeftThenRight": "左上から右",
- "upRightThenLeft": "右上から左"
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ その後 ←",
+ "upThenRight": "↑ その後 →",
+ "upDown": "↑ その後 ↓",
+ "leftThenRight": "← その後 →",
+ "rightThenLeft": "→ その後 ←",
+ "upLeftThenDown": "↖ その後 ↓",
+ "upRightThenDown": "↗ その後 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ その後 ↑",
+ "upThenDownRight": "↑ その後 ↘",
+ "downThenUpRight": "↓ その後 ↗",
+ "rightThenUp": "→ その後 ↑",
+ "rightThenDown": "→ その後 ↓",
+ "downThenRight": "↓ その後 →",
+ "downThenLeft": "↓ その後 ←",
+ "downRightThenUp": "↘ その後 ↑",
+ "downLeftThenUp": "↙ その後 ↑",
+ "upLeftThenRight": "↖ その後 →",
+ "upRightThenLeft": "↗ その後 ←"
},
"favoriteAgentsEmpty": "利用可能なエージェントがありません",
"toasts": {
"renameNeedsSavedSession": "名前の変更は保存済みセッションのみ有効です。まずメッセージを送信してください。",
"sessionFolderNeedsWorkspace": "先にワークスペースフォルダを開いてください。",
- "cycleNeedsMoreAgents": "利用可能なエージェントが1つだけのため、切り替えできません。"
- }
+ "cycleNeedsMoreAgents": "利用可能なエージェントが1つだけのため、切り替えできません。",
+ "noOtherRunning": "切り替え先の実行中セッションがありません",
+ "noOtherRecent": "切り替え先の最近のセッションがありません",
+ "noPlanMode": "このエージェントにPlanモードはありません",
+ "pinToggled": "ピン留め状態を更新しました",
+ "noRunningSession": "実行中のセッションはまだありません",
+ "noModesAvailable": "このエージェントには利用可能なモードがありません。",
+ "noSwitchTarget": "切り替え先のモードがありません(Plan または完全アクセスモードが見つかりません)。"
+ },
+ "recentSessionDepth": "最近セッション切替数",
+ "bindingCleared": "未割り当て"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json
index 8e375dbd77..6819fb8e8d 100644
--- a/src/i18n/messages/ko.json
+++ b/src/i18n/messages/ko.json
@@ -181,6 +181,13 @@
"sectionDescription": "대화 영역의 접기/펼치기, 도구 호출, 작업 상태 등의 애니메이션과 부드러운 스크롤을 제어합니다. 끄면 즉시 갱신됩니다. 스피너는 계속 회전합니다.",
"enable": "채팅 애니메이션 사용"
},
+ "messageNav": {
+ "sectionTitle": "메시지 탐색기",
+ "sectionDescription": "대화 메시지 탐색기의 위치입니다. 오른쪽 아래를 선택하면 사용자 발화마다 한 줄인 컴팩트 카드로 입력창 위에 표시됩니다.",
+ "positionStart": "왼쪽 위(기본)",
+ "positionBottomEnd": "오른쪽 아래(컴팩트)",
+ "hint": "계획 및 하위 에이전트 패널은 항상 왼쪽 위에 남습니다."
+ },
"chatWidth": {
"sectionTitle": "채팅 너비",
"sectionDescription": "대화 영역과 입력창의 최대 너비입니다. 채팅 영역의 좌우 가장자리를 드래그해서 조정할 수도 있습니다.",
@@ -258,60 +265,69 @@
"panelTitle": "빠른 작업"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "탭",
+ "doubleTap": "더블 탭",
+ "longPress": "길게 누름",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 후 ←",
+ "upThenRight": "↑ 후 →",
+ "upDown": "↑ 후 ↓",
+ "leftThenRight": "← 후 →",
+ "rightThenLeft": "→ 후 ←",
+ "upLeftThenDown": "↖ 후 ↓",
+ "upRightThenDown": "↗ 후 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 후 ↑",
+ "upThenDownRight": "↑ 후 ↘",
+ "downThenUpRight": "↓ 후 ↗",
+ "rightThenUp": "→ 후 ↑",
+ "rightThenDown": "→ 후 ↓",
+ "downThenRight": "↓ 후 →",
+ "downThenLeft": "↓ 후 ←",
+ "downRightThenUp": "↘ 후 ↑",
+ "downLeftThenUp": "↙ 후 ↑",
+ "upLeftThenRight": "↖ 후 →",
+ "upRightThenLeft": "↗ 후 ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
- "openCanvas": "Canvas",
- "openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "newConversation": "새 대화",
+ "toggleSidebar": "사이드바 전환",
+ "toggleSearch": "검색",
+ "toggleTerminal": "터미널 전환",
+ "nextTab": "다음 탭",
+ "prevTab": "이전 탭",
+ "reopenClosedTab": "닫은 탭 다시 열기",
+ "openFolder": "폴더 열기",
+ "zoomIn": "확대",
+ "zoomOut": "축소",
+ "zoomReset": "확대/축소 초기화",
+ "stopGenerating": "생성 중지",
+ "openSettings": "설정",
+ "openTodos": "할 일",
+ "openTodosNew": "새 할 일",
+ "openAutomations": "자동화",
+ "openCanvas": "캔버스",
+ "openAgents": "에이전트",
+ "openSystemAdmin": "시스템 관리",
+ "renameConversation": "대화 이름 바꾸기",
+ "openSessionFolder": "세션 파일",
+ "cycleAgent": "다음 에이전트",
+ "cycleFavoriteAgent": "즐겨쓰는 에이전트",
+ "openBallBindings": "제스처 바인딩",
+ "cycleRunningSessions": "실행 중인 세션",
+ "cycleRecentSessions": "최근 세션",
+ "deleteCurrentConversation": "현재 세션 삭제",
+ "openImportSessions": "セッション 가져오기",
+ "togglePinConversation": "고정/고정 해제",
+ "focusModeSelector": "모드 선택",
+ "togglePlanFullAccess": "Plan/전체 권한 전환",
+ "openCollaboration": "협업"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "KIRO_API_KEY로 CLI에 전달됩니다. 비워 두면 kiro-cli login으로 로그인한 계정을 사용합니다. 브라우저 로그인이 불가능한 환경(서버, Docker)에서만 필요합니다.",
"saveConfig": "Kiro 구성 저장"
},
- "trae": {
- "configManagement": "구성 관리",
- "configDescription": "TRAE CLI 2.0은 TRAE 엔터프라이즈 플래그십 요금제 고객만 사용할 수 있습니다. Codeg는 설치된 traecli를 실행하며, 로그인 정보·스킬·MCP 서버는 ~/.trae에 저장됩니다. 모델, 모드, 추론 강도는 여기에 없습니다. TRAE CLI가 ACP로 보고하므로 입력창의 선택기가 세션별로 관리합니다.",
- "signInTitle": "로그인",
- "signInHint": "터미널에서 이 명령을 한 번 실행해 엔터프라이즈 SSO로 로그인하세요. Codeg의 세션은 그 로그인을 재사용합니다.",
- "copyCommand": "명령 복사",
- "commandCopied": "명령을 복사했습니다",
- "patLabel": "개인 액세스 토큰(선택)",
- "patHint": "서버나 Docker처럼 브라우저 로그인이 불가능한 머신용입니다. Codeg는 TRAECLI_PERSONAL_ACCESS_TOKEN으로 TRAE CLI에 전달하고 세션을 시작할 때마다 이 토큰으로 로그인합니다. 비워 두면 traecli login의 로그인을 사용합니다.",
- "hostLabel": "엔터프라이즈 API URL(선택)",
- "hostHint": "조직이 자체 도메인에서 TRAE를 운영하는 경우에만 입력하세요. TRAECLI_HOST로 전달되며, 비워 두면 TRAE 공식 서비스를 사용합니다.",
- "saveConfig": "TRAE CLI 구성 저장"
- },
- "commandCode": {
- "configManagement": "구성 관리",
- "configDescription": "Codeg는 command-code npm 패키지의 Command Code CLI를 실행하며, 로그인 정보·스킬·MCP 서버는 ~/.commandcode에 저장됩니다. 모델, 모드, 추론 강도는 여기에 없습니다. Command Code가 ACP로 보고하므로 입력창의 선택기가 세션별로 관리합니다.",
- "signInTitle": "로그인",
- "signInHint": "터미널에서 이 명령을 한 번 실행해 Command Code 계정으로 로그인하세요. Codeg의 세션은 그 로그인을 재사용합니다.",
- "copyCommand": "명령 복사",
- "commandCopied": "명령을 복사했습니다",
- "apiKeyLabel": "API 키(선택)",
- "apiKeyHint": "서버나 Docker처럼 브라우저 로그인이 불가능한 머신용입니다. COMMAND_CODE_API_KEY로 Command Code에 전달되며 command-code login의 로그인보다 우선합니다. 비워 두면 그 로그인을 사용합니다.",
- "saveConfig": "Command Code 구성 저장"
- },
"deepseek": {
"configManagement": "DeepSeek Harness 구성",
"configDescription": "엔드포인트와 API 키는 deepseek-acp가 시작할 때 읽는 환경 변수입니다. 모델과 추론 강도는 세션별 선택기이므로 입력창에서 바꿉니다.",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Kiro 구성을 저장했습니다",
"saveKiroFailed": "Kiro 구성을 저장하지 못했습니다",
- "traeSaved": "TRAE CLI 구성을 저장했습니다",
- "saveTraeFailed": "TRAE CLI 구성을 저장하지 못했습니다",
- "commandCodeSaved": "Command Code 구성을 저장했습니다",
- "saveCommandCodeFailed": "Command Code 구성을 저장하지 못했습니다",
"systemAgentAlreadyLatest": "{name}은(는) 이미 최신 버전입니다({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "커밋"
},
"noFolderTitle": "열린 폴더 없음",
- "noFolderHint": "폴더를 열면 여기에 표시됩니다",
- "openFullPage": "전체 페이지에서 열기",
- "back": "뒤로",
- "noAutomations": "이 프로젝트에는 아직 자동화가 없습니다"
+ "noFolderHint": "폴더를 열면 여기에 표시됩니다"
},
"windowControls": {
"minimizeWindow": "창 최소화",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "무엇이든 물어보세요...",
- "promptSuggestion": "{suggestion} (Tab 키로 입력)",
"removeAttachmentAria": "{name} 제거",
"attachFiles": "파일 첨부",
"addActions": "추가",
@@ -3411,10 +3395,6 @@
"searchModelAria": "모델 검색",
"modelListLabel": "모델",
"recommendedBadge": "권장",
- "recommendedValue": "권장: {value}",
- "searchOptions": "옵션 검색...",
- "searchOptionsAria": "옵션 검색",
- "noOptions": "옵션을 찾을 수 없습니다",
"noModels": "모델을 찾을 수 없습니다",
"cancel": "취소",
"send": "보내기",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "메시지 탐색",
+ "collapse": "메시지 탐색 접기",
"loadingEarlier": "이전 메시지를 불러오는 중…",
"loadEarlier": "이전 메시지 불러오기",
+ "collapsedSummary": "메시지 {count}",
"fileCount": "{count, plural, one {#개 파일} other {#개 파일}}",
- "subAgentCount": "{count, plural, one {서브 에이전트 #개} other {서브 에이전트 #개}}",
- "showDiff": "{filePath}의 변경 사항 보기",
- "hideDiff": "{filePath}의 변경 사항 숨기기",
- "openFile": "{filePath} 열기",
- "collapse": "접기",
- "currentMessage": "현재 메시지",
- "scrollToCurrent": "현재 메시지(#{ordinal})로 스크롤"
+ "remove": "제거",
+ "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다"
},
"replyArtifacts": {
"title": "변경된 파일",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "작업 {task} 재개 중",
"resumeDelegationNoId": "위임 작업 재개 중",
"promptLabel": "프롬프트",
- "ackRecorded": "작업 항목에 기록됨",
- "ackNotRecorded": "작업 항목에 기록되지 않음",
- "ackNotRecordedWithReason": "작업 항목에 기록되지 않음: {reason}",
"verdict": {
"success": "성공",
"needs_review": "검토 필요",
@@ -4214,18 +4188,6 @@
"stopDeclined": "해당 작업을 중지할 수 없습니다. 이미 완료되었을 수 있습니다.",
"stopFailed": "작업 중지에 실패했습니다: {error}"
},
- "remoteControl": {
- "title": "원격 제어 켜짐",
- "open": "브라우저에서 열기",
- "copy": "링크 복사",
- "copied": "복사됨",
- "qr": "QR 코드",
- "qrLabel": "이 세션의 원격 제어 링크 QR 코드",
- "qrHint": "휴대폰으로 스캔하면 Claude 앱이나 claude.ai/code에서 이 세션을 이어갈 수 있습니다.",
- "noUrl": "Claude Code가 이 세션의 링크를 반환하지 않았습니다",
- "turnOff": "끄기",
- "turnOffBusy": "Claude가 작업을 마치면 사용할 수 있습니다"
- },
"proposedPlan": {
"title": "제안된 계획",
"planning": "계획 중…"
@@ -7433,44 +7395,62 @@
"renameConversation": "대화 이름 바꾸기",
"openSessionFolder": "세션 파일",
"cycleAgent": "다음 에이전트",
- "cycleFavoriteAgent": "즐겨쓰는 에이전트"
+ "cycleFavoriteAgent": "즐겨쓰는 에이전트",
+ "openBallBindings": "제스처 바인딩",
+ "cycleRunningSessions": "실행 중인 세션",
+ "cycleRecentSessions": "최근 세션",
+ "deleteCurrentConversation": "현재 세션 삭제",
+ "openImportSessions": "セッション 가져오기",
+ "togglePinConversation": "고정/고정 해제",
+ "focusModeSelector": "모드 선택",
+ "togglePlanFullAccess": "Plan/전체 권한 전환",
+ "openCollaboration": "협업"
},
"gestures": {
"tap": "탭",
"doubleTap": "더블 탭",
- "longPress": "길게 누르기",
- "left": "왼쪽 스와이프",
- "right": "오른쪽 스와이프",
- "up": "위로 스와이프",
- "upLeft": "왼쪽 위",
- "upRight": "오른쪽 위",
- "upThenLeft": "위 → 왼쪽",
- "upThenRight": "위 → 오른쪽",
- "upDown": "위 → 아래",
- "leftThenRight": "왼쪽 → 오른쪽",
- "rightThenLeft": "오른쪽 → 왼쪽",
- "upLeftThenDown": "왼쪽 위 → 아래",
- "upRightThenDown": "오른쪽 위 → 아래",
- "down": "아래로",
- "downLeft": "왼쪽 아래",
- "downRight": "오른쪽 아래",
- "downUp": "아래→위",
- "upThenDownRight": "위→오른아래",
- "downThenUpRight": "아래→오른위",
- "rightThenUp": "오른→위",
- "rightThenDown": "오른→아래",
- "downThenRight": "아래→오른",
- "downThenLeft": "아래→왼",
- "downRightThenUp": "오른아래→위",
- "downLeftThenUp": "왼아래→위",
- "upLeftThenRight": "왼위→오른",
- "upRightThenLeft": "오른위→왼"
+ "longPress": "길게 누름",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 후 ←",
+ "upThenRight": "↑ 후 →",
+ "upDown": "↑ 후 ↓",
+ "leftThenRight": "← 후 →",
+ "rightThenLeft": "→ 후 ←",
+ "upLeftThenDown": "↖ 후 ↓",
+ "upRightThenDown": "↗ 후 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 후 ↑",
+ "upThenDownRight": "↑ 후 ↘",
+ "downThenUpRight": "↓ 후 ↗",
+ "rightThenUp": "→ 후 ↑",
+ "rightThenDown": "→ 후 ↓",
+ "downThenRight": "↓ 후 →",
+ "downThenLeft": "↓ 후 ←",
+ "downRightThenUp": "↘ 후 ↑",
+ "downLeftThenUp": "↙ 후 ↑",
+ "upLeftThenRight": "↖ 후 →",
+ "upRightThenLeft": "↗ 후 ←"
},
"favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다",
"toasts": {
"renameNeedsSavedSession": "이름 바꾸기는 저장된 세션에만 적용됩니다. 먼저 메시지를 보내세요.",
"sessionFolderNeedsWorkspace": "먼저 작업 공간 폴더를 여세요.",
- "cycleNeedsMoreAgents": "사용 가능한 에이전트가 하나뿐이어서 전환할 수 없습니다."
- }
+ "cycleNeedsMoreAgents": "사용 가능한 에이전트가 하나뿐이어서 전환할 수 없습니다.",
+ "noOtherRunning": "전환할 다른 실행 세션이 없습니다",
+ "noOtherRecent": "전환할 다른 최근 세션이 없습니다",
+ "noPlanMode": "이 에이전트에 Plan 모드가 없습니다",
+ "pinToggled": "고정 상태가 변경되었습니다",
+ "noRunningSession": "아직 실행 중인 세션이 없습니다",
+ "noModesAvailable": "이 에이전트에는 사용 가능한 모드가 없습니다.",
+ "noSwitchTarget": "전환할 모드가 없습니다(Plan 또는 전체 접근 모드를 찾을 수 없음)."
+ },
+ "recentSessionDepth": "최근 세션 전환 깊이",
+ "bindingCleared": "미지정"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json
index acc64d9b91..9e1bc0c918 100644
--- a/src/i18n/messages/pt.json
+++ b/src/i18n/messages/pt.json
@@ -181,6 +181,13 @@
"sectionDescription": "Animações de recolher/expandir, chamadas de ferramentas e estado de trabalho na área de conversa, além da rolagem suave. Desative para atualizações instantâneas. Os indicadores de carregamento continuam girando.",
"enable": "Ativar as animações do chat"
},
+ "messageNav": {
+ "sectionTitle": "Navegador de mensagens",
+ "sectionDescription": "Posição do navegador de mensagens. No canto inferior direito vira um cartão compacto com uma linha por mensagem do usuário, acima do campo de entrada.",
+ "positionStart": "Canto superior esquerdo (padrão)",
+ "positionBottomEnd": "Canto inferior direito (compacto)",
+ "hint": "Os painéis de plano e de subagentes permanecem no canto superior esquerdo."
+ },
"chatWidth": {
"sectionTitle": "Largura do chat",
"sectionDescription": "Largura máxima da coluna de conversa e da caixa de entrada. Você também pode arrastar as bordas do chat para ajustá-la.",
@@ -258,60 +265,69 @@
"panelTitle": "Ações rápidas"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "Toque",
+ "doubleTap": "Toque duplo",
+ "longPress": "Pressão longa",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ depois ←",
+ "upThenRight": "↑ depois →",
+ "upDown": "↑ depois ↓",
+ "leftThenRight": "← depois →",
+ "rightThenLeft": "→ depois ←",
+ "upLeftThenDown": "↖ depois ↓",
+ "upRightThenDown": "↗ depois ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ depois ↑",
+ "upThenDownRight": "↑ depois ↘",
+ "downThenUpRight": "↓ depois ↗",
+ "rightThenUp": "→ depois ↑",
+ "rightThenDown": "→ depois ↓",
+ "downThenRight": "↓ depois →",
+ "downThenLeft": "↓ depois ←",
+ "downRightThenUp": "↘ depois ↑",
+ "downLeftThenUp": "↙ depois ↑",
+ "upLeftThenRight": "↖ depois →",
+ "upRightThenLeft": "↗ depois ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
+ "newConversation": "Nova conversa",
+ "toggleSidebar": "Alternar barra lateral",
+ "toggleSearch": "Pesquisar",
+ "toggleTerminal": "Alternar terminal",
+ "nextTab": "Próxima aba",
+ "prevTab": "Aba anterior",
+ "reopenClosedTab": "Reabrir aba fechada",
+ "openFolder": "Abrir pasta",
+ "zoomIn": "Aumentar zoom",
+ "zoomOut": "Diminuir zoom",
+ "zoomReset": "Redefinir zoom",
+ "stopGenerating": "Parar geração",
+ "openSettings": "Configurações",
+ "openTodos": "Tarefas",
+ "openTodosNew": "Nova tarefa",
+ "openAutomations": "Automações",
"openCanvas": "Canvas",
- "openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "openAgents": "Agentes",
+ "openSystemAdmin": "Administração",
+ "renameConversation": "Renomear conversa",
+ "openSessionFolder": "Arquivos da sessão",
+ "cycleAgent": "Próximo agente",
+ "cycleFavoriteAgent": "Agentes favoritos",
+ "openBallBindings": "Atalhos de gestos",
+ "cycleRunningSessions": "Sessões em execução",
+ "cycleRecentSessions": "Sessões recentes",
+ "deleteCurrentConversation": "Excluir sessão atual",
+ "openImportSessions": "Importar sessões",
+ "togglePinConversation": "Fixar / desafixar",
+ "focusModeSelector": "Seletor de modo",
+ "togglePlanFullAccess": "Plano / acesso total",
+ "openCollaboration": "Colaboração"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "Passada à CLI como KIRO_API_KEY. Deixe vazia para usar a conta conectada via kiro-cli login; só é necessária onde não há login pelo navegador (servidores, Docker).",
"saveConfig": "Salvar configuração do Kiro"
},
- "trae": {
- "configManagement": "Configuração",
- "configDescription": "O TRAE CLI 2.0 está disponível apenas para clientes do plano principal do TRAE Enterprise. O Codeg executa o traecli que você instalou, que guarda o login, as skills e os servidores MCP em ~/.trae. Modelo, modo e esforço de raciocínio não ficam aqui: o TRAE CLI os informa via ACP, então os seletores do compositor os gerenciam em cada sessão.",
- "signInTitle": "Entrar",
- "signInHint": "Execute isto uma vez em um terminal para entrar com o SSO da sua empresa. As sessões do Codeg reutilizam esse login.",
- "copyCommand": "Copiar comando",
- "commandCopied": "Comando copiado",
- "patLabel": "Token de acesso pessoal (opcional)",
- "patHint": "Para uma máquina em que não é possível entrar pelo navegador, como um servidor ou uma instalação Docker. O Codeg o passa ao TRAE CLI como TRAECLI_PERSONAL_ACCESS_TOKEN e entra com ele sempre que uma sessão começa. Deixe vazio para usar o login do traecli login.",
- "hostLabel": "URL da API corporativa (opcional)",
- "hostHint": "Somente se a sua organização executa o TRAE em um domínio próprio. É passada como TRAECLI_HOST; deixe vazia para usar o serviço do TRAE.",
- "saveConfig": "Salvar configuração do TRAE CLI"
- },
- "commandCode": {
- "configManagement": "Configuração",
- "configDescription": "O Codeg executa a CLI do Command Code do pacote npm command-code, que guarda o login, as skills e os servidores MCP em ~/.commandcode. Modelo, modo e esforço de raciocínio não ficam aqui: o Command Code os informa via ACP, então os seletores do compositor os gerenciam em cada sessão.",
- "signInTitle": "Entrar",
- "signInHint": "Execute isto uma vez em um terminal para entrar com sua conta do Command Code. As sessões do Codeg reutilizam esse login.",
- "copyCommand": "Copiar comando",
- "commandCopied": "Comando copiado",
- "apiKeyLabel": "Chave de API (opcional)",
- "apiKeyHint": "Para uma máquina em que não é possível entrar pelo navegador, como um servidor ou uma instalação Docker. Passada ao Command Code como COMMAND_CODE_API_KEY, que tem prioridade sobre o login do command-code login. Deixe vazia para usar esse login.",
- "saveConfig": "Salvar configuração do Command Code"
- },
"deepseek": {
"configManagement": "Configuração do DeepSeek Harness",
"configDescription": "O endpoint e a chave são variáveis de ambiente que o deepseek-acp lê ao iniciar. O modelo e o nível de raciocínio são seletores por sessão — escolha-os no campo de mensagem.",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Configuração do Kiro salva",
"saveKiroFailed": "Falha ao salvar a configuração do Kiro",
- "traeSaved": "Configuração do TRAE CLI salva",
- "saveTraeFailed": "Falha ao salvar a configuração do TRAE CLI",
- "commandCodeSaved": "Configuração do Command Code salva",
- "saveCommandCodeFailed": "Falha ao salvar a configuração do Command Code",
"systemAgentAlreadyLatest": "{name} já está atualizado ({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "Confirmações"
},
"noFolderTitle": "Nenhuma pasta aberta",
- "noFolderHint": "Abra uma pasta para ver seu conteúdo aqui",
- "openFullPage": "Abrir em página inteira",
- "back": "Voltar",
- "noAutomations": "Este projeto ainda não tem automações"
+ "noFolderHint": "Abra uma pasta para ver seu conteúdo aqui"
},
"windowControls": {
"minimizeWindow": "Minimizar janela",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "Pergunte qualquer coisa...",
- "promptSuggestion": "{suggestion} (Tab para usar)",
"removeAttachmentAria": "Remover {name}",
"attachFiles": "Anexar arquivos",
"addActions": "Adicionar",
@@ -3411,10 +3395,6 @@
"searchModelAria": "Buscar modelos",
"modelListLabel": "Modelos",
"recommendedBadge": "Recomendado",
- "recommendedValue": "Recomendado: {value}",
- "searchOptions": "Buscar opções...",
- "searchOptionsAria": "Buscar opções",
- "noOptions": "Nenhuma opção encontrada",
"noModels": "Nenhum modelo encontrado",
"cancel": "Cancelar",
"send": "Enviar",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "Navegação de mensagens",
+ "collapse": "Recolher navegação de mensagens",
"loadingEarlier": "Carregando mensagens anteriores…",
"loadEarlier": "Carregar mensagens anteriores",
+ "collapsedSummary": "Mensagens {count}",
"fileCount": "{count, plural, one {# arquivo} other {# arquivos}}",
- "subAgentCount": "{count, plural, one {# subagente} other {# subagentes}}",
- "showDiff": "Mostrar as alterações de {filePath}",
- "hideDiff": "Ocultar as alterações de {filePath}",
- "openFile": "Abrir {filePath}",
- "collapse": "Recolher",
- "currentMessage": "Mensagem atual",
- "scrollToCurrent": "Rolar até a mensagem atual (#{ordinal})"
+ "remove": "Remover",
+ "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}"
},
"replyArtifacts": {
"title": "Arquivos alterados",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "Retomando a tarefa {task}",
"resumeDelegationNoId": "Retomando uma tarefa delegada",
"promptLabel": "Instrução",
- "ackRecorded": "Registrado na tarefa de trabalho",
- "ackNotRecorded": "Não registrado na tarefa de trabalho",
- "ackNotRecordedWithReason": "Não registrado na tarefa de trabalho: {reason}",
"verdict": {
"success": "sucesso",
"needs_review": "requer revisão",
@@ -4214,18 +4188,6 @@
"stopDeclined": "Não foi possível parar essa tarefa — ela pode já ter terminado.",
"stopFailed": "Falha ao parar a tarefa: {error}"
},
- "remoteControl": {
- "title": "Controle remoto ativado",
- "open": "Abrir no navegador",
- "copy": "Copiar link",
- "copied": "Copiado",
- "qr": "Código QR",
- "qrLabel": "Código QR do link de controle remoto desta sessão",
- "qrHint": "Escaneie com o celular para continuar esta sessão no app do Claude ou em claude.ai/code.",
- "noUrl": "O Claude Code não retornou nenhum link para esta sessão",
- "turnOff": "Desativar",
- "turnOffBusy": "Disponível quando o Claude terminar"
- },
"proposedPlan": {
"title": "Plano proposto",
"planning": "A planear…"
@@ -7433,44 +7395,62 @@
"renameConversation": "Renomear conversa",
"openSessionFolder": "Arquivos da sessão",
"cycleAgent": "Próximo agente",
- "cycleFavoriteAgent": "Agentes favoritos"
+ "cycleFavoriteAgent": "Agentes favoritos",
+ "openBallBindings": "Atalhos de gestos",
+ "cycleRunningSessions": "Sessões em execução",
+ "cycleRecentSessions": "Sessões recentes",
+ "deleteCurrentConversation": "Excluir sessão atual",
+ "openImportSessions": "Importar sessões",
+ "togglePinConversation": "Fixar / desafixar",
+ "focusModeSelector": "Seletor de modo",
+ "togglePlanFullAccess": "Plano / acesso total",
+ "openCollaboration": "Colaboração"
},
"gestures": {
"tap": "Toque",
"doubleTap": "Toque duplo",
- "longPress": "Toque longo",
- "left": "Deslizar para a esquerda",
- "right": "Deslizar para a direita",
- "up": "Deslizar para cima",
- "upLeft": "Cima-esquerda",
- "upRight": "Cima-direita",
- "upThenLeft": "Cima, depois esquerda",
- "upThenRight": "Cima, depois direita",
- "upDown": "Cima, depois baixo",
- "leftThenRight": "Esquerda, depois direita",
- "rightThenLeft": "Direita, depois esquerda",
- "upLeftThenDown": "Cima-esquerda, depois baixo",
- "upRightThenDown": "Cima-direita, depois baixo",
- "down": "Deslizar para baixo",
- "downLeft": "Baixo-esq.",
- "downRight": "Baixo-dir.",
- "downUp": "Baixo, depois cima",
- "upThenDownRight": "Cima, depois baixo-dir.",
- "downThenUpRight": "Baixo, depois cima-dir.",
- "rightThenUp": "Direita, depois cima",
- "rightThenDown": "Direita, depois baixo",
- "downThenRight": "Baixo, depois direita",
- "downThenLeft": "Baixo, depois esquerda",
- "downRightThenUp": "Baixo-dir., depois cima",
- "downLeftThenUp": "Baixo-esq., depois cima",
- "upLeftThenRight": "Cima-esq., depois direita",
- "upRightThenLeft": "Cima-dir., depois esquerda"
+ "longPress": "Pressão longa",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ depois ←",
+ "upThenRight": "↑ depois →",
+ "upDown": "↑ depois ↓",
+ "leftThenRight": "← depois →",
+ "rightThenLeft": "→ depois ←",
+ "upLeftThenDown": "↖ depois ↓",
+ "upRightThenDown": "↗ depois ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ depois ↑",
+ "upThenDownRight": "↑ depois ↘",
+ "downThenUpRight": "↓ depois ↗",
+ "rightThenUp": "→ depois ↑",
+ "rightThenDown": "→ depois ↓",
+ "downThenRight": "↓ depois →",
+ "downThenLeft": "↓ depois ←",
+ "downRightThenUp": "↘ depois ↑",
+ "downLeftThenUp": "↙ depois ↑",
+ "upLeftThenRight": "↖ depois →",
+ "upRightThenLeft": "↗ depois ←"
},
"favoriteAgentsEmpty": "Nenhum agente disponível",
"toasts": {
"renameNeedsSavedSession": "Renomear só funciona em sessões salvas — envie uma mensagem primeiro.",
"sessionFolderNeedsWorkspace": "Abra antes uma pasta de espaço de trabalho.",
- "cycleNeedsMoreAgents": "Só há um agente disponível — nada para alternar."
- }
+ "cycleNeedsMoreAgents": "Só há um agente disponível — nada para alternar.",
+ "noOtherRunning": "Nenhuma outra sessão em execução.",
+ "noOtherRecent": "Nenhuma outra sessão recente.",
+ "noPlanMode": "Este agente não tem modo Plano.",
+ "pinToggled": "Estado de fixação atualizado.",
+ "noRunningSession": "Ainda não há sessão em execução.",
+ "noModesAvailable": "Este agente não expõe nenhum modo.",
+ "noSwitchTarget": "Nenhum modo para alternar (modo Plan ou de acesso completo não encontrado)."
+ },
+ "recentSessionDepth": "Profundidade de sessões recentes",
+ "bindingCleared": "Sem atribuição"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json
index 45f4b49a8a..db78c4acfc 100644
--- a/src/i18n/messages/zh-CN.json
+++ b/src/i18n/messages/zh-CN.json
@@ -181,6 +181,13 @@
"sectionDescription": "会话区域内的折叠/展开、工具调用、工作状态等动画,以及平滑滚动。关闭后界面立即更新、不再有过渡动画;加载转圈图标仍会旋转。",
"enable": "启用聊天区域动画"
},
+ "messageNav": {
+ "sectionTitle": "消息导航",
+ "sectionDescription": "会话消息导航卡的位置。右下角会变成紧凑卡片:每次用户回话一行,贴在输入框上方,不挡阅读区。",
+ "positionStart": "左上(默认)",
+ "positionBottomEnd": "右下(紧凑)",
+ "hint": "计划面板与子智能体面板始终留在左上。"
+ },
"chatWidth": {
"sectionTitle": "聊天区域宽度",
"sectionDescription": "会话列与输入框的最大宽度。也可以直接拖动聊天区域左右两侧的边缘来调整。",
@@ -258,60 +265,69 @@
"panelTitle": "快捷操作"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "单击",
+ "doubleTap": "双击",
+ "longPress": "长按",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 然后 ←",
+ "upThenRight": "↑ 然后 →",
+ "upDown": "↑ 然后 ↓",
+ "leftThenRight": "← 然后 →",
+ "rightThenLeft": "→ 然后 ←",
+ "upLeftThenDown": "↖ 然后 ↓",
+ "upRightThenDown": "↗ 然后 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 然后 ↑",
+ "upThenDownRight": "↑ 然后 ↘",
+ "downThenUpRight": "↓ 然后 ↗",
+ "rightThenUp": "→ 然后 ↑",
+ "rightThenDown": "→ 然后 ↓",
+ "downThenRight": "↓ 然后 →",
+ "downThenLeft": "↓ 然后 ←",
+ "downRightThenUp": "↘ 然后 ↑",
+ "downLeftThenUp": "↙ 然后 ↑",
+ "upLeftThenRight": "↖ 然后 →",
+ "upRightThenLeft": "↗ 然后 ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
- "openCanvas": "Canvas",
- "openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "newConversation": "新建会话",
+ "toggleSidebar": "切换侧栏",
+ "toggleSearch": "搜索",
+ "toggleTerminal": "切换终端",
+ "nextTab": "下一个标签",
+ "prevTab": "上一个标签",
+ "reopenClosedTab": "恢复关闭的标签",
+ "openFolder": "打开文件夹",
+ "zoomIn": "放大",
+ "zoomOut": "缩小",
+ "zoomReset": "重置缩放",
+ "stopGenerating": "停止生成",
+ "openSettings": "设置",
+ "openTodos": "待办任务",
+ "openTodosNew": "新建待办",
+ "openAutomations": "自动化",
+ "openCanvas": "无限画布",
+ "openAgents": "智能体",
+ "openSystemAdmin": "系统管理",
+ "renameConversation": "重命名会话",
+ "openSessionFolder": "会话文件",
+ "cycleAgent": "下一个智能体",
+ "cycleFavoriteAgent": "常用智能体",
+ "openBallBindings": "手势绑定",
+ "cycleRunningSessions": "运行中的会话",
+ "cycleRecentSessions": "最近的会话",
+ "deleteCurrentConversation": "删除当前会话",
+ "openImportSessions": "导入会话",
+ "togglePinConversation": "置顶/取消置顶",
+ "focusModeSelector": "模式选择",
+ "togglePlanFullAccess": "Plan/全权限切换",
+ "openCollaboration": "协作"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "以 KIRO_API_KEY 传给 CLI。留空则使用 kiro-cli login 登录的账号;只有无法用浏览器登录的环境(服务器、Docker)才需要 API Key。",
"saveConfig": "保存 Kiro 配置"
},
- "trae": {
- "configManagement": "配置管理",
- "configDescription": "TRAE CLI 2.0 仅向 TRAE 企业版旗舰版套餐客户开放。Codeg 运行你安装的 traecli,它把登录状态、技能和 MCP 服务器保存在 ~/.trae 中。模型、模式和推理强度不在这里设置:TRAE CLI 会通过 ACP 上报它们,由输入框自带的选择器按会话管理。",
- "signInTitle": "登录",
- "signInHint": "在终端中运行一次下面的命令,用企业 SSO 登录。Codeg 里的会话会复用这次登录。",
- "copyCommand": "复制命令",
- "commandCopied": "命令已复制",
- "patLabel": "个人访问令牌(可选)",
- "patHint": "适用于无法用浏览器登录的机器,例如服务器或 Docker 部署。Codeg 会以 TRAECLI_PERSONAL_ACCESS_TOKEN 传给 TRAE CLI,并在每次启动会话时用它登录。留空则使用 traecli login 的登录。",
- "hostLabel": "企业 API 地址(可选)",
- "hostHint": "仅当你的组织在自有域名上部署 TRAE 时填写。以 TRAECLI_HOST 传入;留空则使用 TRAE 官方服务。",
- "saveConfig": "保存 TRAE CLI 配置"
- },
- "commandCode": {
- "configManagement": "配置管理",
- "configDescription": "Codeg 运行 command-code npm 包提供的 Command Code CLI,它把登录状态、技能和 MCP 服务器保存在 ~/.commandcode 中。模型、模式和推理强度不在这里设置:Command Code 会通过 ACP 上报它们,由输入框自带的选择器按会话管理。",
- "signInTitle": "登录",
- "signInHint": "在终端中运行一次下面的命令,登录你的 Command Code 账号。Codeg 里的会话会复用这次登录。",
- "copyCommand": "复制命令",
- "commandCopied": "命令已复制",
- "apiKeyLabel": "API 密钥(可选)",
- "apiKeyHint": "适用于无法用浏览器登录的机器,例如服务器或 Docker 部署。以 COMMAND_CODE_API_KEY 传给 Command Code,优先于 command-code login 的登录。留空则使用那次登录。",
- "saveConfig": "保存 Command Code 配置"
- },
"deepseek": {
"configManagement": "DeepSeek Harness 配置",
"configDescription": "端点与密钥是 deepseek-acp 启动时读取的环境变量。模型和推理档位是会话级选择器,在输入框里切换。",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "保存 Antigravity 配置失败",
"kiroSaved": "Kiro 配置已保存",
"saveKiroFailed": "保存 Kiro 配置失败",
- "traeSaved": "TRAE CLI 配置已保存",
- "saveTraeFailed": "保存 TRAE CLI 配置失败",
- "commandCodeSaved": "Command Code 配置已保存",
- "saveCommandCodeFailed": "保存 Command Code 配置失败",
"systemAgentAlreadyLatest": "{name} 已是最新版本({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "提交"
},
"noFolderTitle": "暂无打开的文件夹",
- "noFolderHint": "打开一个文件夹后在这里查看",
- "openFullPage": "在完整页面中打开",
- "back": "返回",
- "noAutomations": "此项目还没有自动化"
+ "noFolderHint": "打开一个文件夹后在这里查看"
},
"windowControls": {
"minimizeWindow": "最小化窗口",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "请开始输入...",
- "promptSuggestion": "{suggestion}(按 Tab 填入)",
"removeAttachmentAria": "移除 {name}",
"attachFiles": "附加文件",
"attachLocalUpload": "附加本地文件",
@@ -3413,10 +3397,6 @@
"searchModelAria": "搜索模型",
"modelListLabel": "模型",
"recommendedBadge": "推荐",
- "recommendedValue": "推荐:{value}",
- "searchOptions": "搜索选项...",
- "searchOptionsAria": "搜索选项",
- "noOptions": "未找到选项",
"noModels": "未找到模型",
"cancel": "取消",
"send": "发送",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "消息导航",
+ "collapse": "收起消息导航",
"loadingEarlier": "正在加载更早的消息…",
"loadEarlier": "加载更早的消息",
+ "collapsedSummary": "消息 {count}",
"fileCount": "{count} 个文件",
- "subAgentCount": "{count} 个子智能体",
- "showDiff": "展开 {filePath} 的改动",
- "hideDiff": "收起 {filePath} 的改动",
- "openFile": "打开 {filePath}",
- "collapse": "收起",
- "currentMessage": "当前消息",
- "scrollToCurrent": "滚动到当前消息(#{ordinal})"
+ "remove": "移除",
+ "noDiffDataAvailable": "未找到 {filePath} 的差异数据"
},
"replyArtifacts": {
"title": "改动文件",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "恢复任务 {task}",
"resumeDelegationNoId": "恢复委派任务",
"promptLabel": "指令",
- "ackRecorded": "已记录到待办任务",
- "ackNotRecorded": "未记录到待办任务",
- "ackNotRecordedWithReason": "未记录到待办任务:{reason}",
"verdict": {
"success": "成功",
"needs_review": "待复核",
@@ -4214,18 +4188,6 @@
"stopDeclined": "无法停止该任务,它可能已经结束。",
"stopFailed": "停止任务失败:{error}"
},
- "remoteControl": {
- "title": "远程控制已开启",
- "open": "在浏览器中打开",
- "copy": "复制链接",
- "copied": "已复制",
- "qr": "二维码",
- "qrLabel": "本会话远程控制链接的二维码",
- "qrHint": "用手机扫码,在 Claude App 或 claude.ai/code 上继续本会话。",
- "noUrl": "Claude Code 没有返回本会话的链接",
- "turnOff": "关闭",
- "turnOffBusy": "Claude 完成当前工作后可用"
- },
"proposedPlan": {
"title": "计划提案",
"planning": "规划中…"
@@ -7433,44 +7395,62 @@
"renameConversation": "重命名会话",
"openSessionFolder": "会话文件",
"cycleAgent": "下一个智能体",
- "cycleFavoriteAgent": "常用智能体"
+ "cycleFavoriteAgent": "常用智能体",
+ "openBallBindings": "手势绑定",
+ "cycleRunningSessions": "运行中的会话",
+ "cycleRecentSessions": "最近的会话",
+ "deleteCurrentConversation": "删除当前会话",
+ "openImportSessions": "导入会话",
+ "togglePinConversation": "置顶/取消置顶",
+ "focusModeSelector": "模式选择",
+ "togglePlanFullAccess": "Plan/全权限切换",
+ "openCollaboration": "协作"
},
"gestures": {
"tap": "单击",
"doubleTap": "双击",
"longPress": "长按",
- "left": "左滑",
- "right": "右滑",
- "up": "上滑",
- "upLeft": "左上滑",
- "upRight": "右上滑",
- "upThenLeft": "上滑后左滑",
- "upThenRight": "上滑后右滑",
- "upDown": "上滑后下滑",
- "leftThenRight": "左滑后右滑",
- "rightThenLeft": "右滑后左滑",
- "upLeftThenDown": "左上滑后下滑",
- "upRightThenDown": "右上滑后下滑",
- "down": "下滑",
- "downLeft": "左下",
- "downRight": "右下",
- "downUp": "下再上",
- "upThenDownRight": "上再右下",
- "downThenUpRight": "下再右上",
- "rightThenUp": "右再上",
- "rightThenDown": "右再下",
- "downThenRight": "下再右",
- "downThenLeft": "下再左",
- "downRightThenUp": "右下再上",
- "downLeftThenUp": "左下再上",
- "upLeftThenRight": "左上再右",
- "upRightThenLeft": "右上再左"
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 然后 ←",
+ "upThenRight": "↑ 然后 →",
+ "upDown": "↑ 然后 ↓",
+ "leftThenRight": "← 然后 →",
+ "rightThenLeft": "→ 然后 ←",
+ "upLeftThenDown": "↖ 然后 ↓",
+ "upRightThenDown": "↗ 然后 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 然后 ↑",
+ "upThenDownRight": "↑ 然后 ↘",
+ "downThenUpRight": "↓ 然后 ↗",
+ "rightThenUp": "→ 然后 ↑",
+ "rightThenDown": "→ 然后 ↓",
+ "downThenRight": "↓ 然后 →",
+ "downThenLeft": "↓ 然后 ←",
+ "downRightThenUp": "↘ 然后 ↑",
+ "downLeftThenUp": "↙ 然后 ↑",
+ "upLeftThenRight": "↖ 然后 →",
+ "upRightThenLeft": "↗ 然后 ←"
},
"favoriteAgentsEmpty": "暂无可用智能体",
"toasts": {
"renameNeedsSavedSession": "重命名只对已保存的会话生效——先发一条消息。",
"sessionFolderNeedsWorkspace": "请先打开一个工作区文件夹。",
- "cycleNeedsMoreAgents": "可用智能体只有一个,无可切换。"
- }
+ "cycleNeedsMoreAgents": "可用智能体只有一个,无可切换。",
+ "noOtherRunning": "没有其他运行中的会话",
+ "noOtherRecent": "没有其他最近的会话",
+ "noPlanMode": "当前智能体没有 Plan 模式",
+ "pinToggled": "置顶状态已更新",
+ "noRunningSession": "还没有运行中的会话",
+ "noModesAvailable": "该智能体没有可用模式。",
+ "noSwitchTarget": "没有可切换的模式(未找到 Plan 或完整访问模式)。"
+ },
+ "recentSessionDepth": "最近会话切换深度",
+ "bindingCleared": "未绑定"
}
-}
+}
\ No newline at end of file
diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json
index bdcb6dfb2d..5abd210c9e 100644
--- a/src/i18n/messages/zh-TW.json
+++ b/src/i18n/messages/zh-TW.json
@@ -181,6 +181,13 @@
"sectionDescription": "對話區域內的摺疊/展開、工具呼叫、工作狀態等動畫,以及平滑捲動。關閉後介面會立即更新、不再有過渡動畫;載入轉圈圖示仍會旋轉。",
"enable": "啟用聊天區域動畫"
},
+ "messageNav": {
+ "sectionTitle": "訊息導覽",
+ "sectionDescription": "對話訊息導覽卡的位置。右下角會變成緊湊卡片:每次使用者回話一行,貼在輸入框上方,不擋閱讀區。",
+ "positionStart": "左上(預設)",
+ "positionBottomEnd": "右下(緊湊)",
+ "hint": "計畫面板與子代理面板始終留在左上。"
+ },
"chatWidth": {
"sectionTitle": "聊天區域寬度",
"sectionDescription": "對話列與輸入框的最大寬度。也可以直接拖曳聊天區域左右兩側的邊緣來調整。",
@@ -258,60 +265,69 @@
"panelTitle": "快捷操作"
},
"gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "Swipe left",
- "right": "Swipe right",
- "up": "Swipe up",
- "upLeft": "Up-left",
- "upRight": "Up-right",
- "upThenLeft": "Up, then left",
- "upThenRight": "Up, then right",
- "upDown": "Up, then down",
- "leftThenRight": "Left, then right",
- "rightThenLeft": "Right, then left",
- "upLeftThenDown": "Up-left, then down",
- "upRightThenDown": "Up-right, then down",
- "down": "Swipe down",
- "downLeft": "Down-left",
- "downRight": "Down-right",
- "downUp": "Down, then up",
- "upThenDownRight": "Up, then down-right",
- "downThenUpRight": "Down, then up-right",
- "rightThenUp": "Right, then up",
- "rightThenDown": "Right, then down",
- "downThenRight": "Down, then right",
- "downThenLeft": "Down, then left",
- "downRightThenUp": "Down-right, then up",
- "downLeftThenUp": "Down-left, then up",
- "upLeftThenRight": "Up-left, then right",
- "upRightThenLeft": "Up-right, then left"
+ "tap": "單擊",
+ "doubleTap": "雙擊",
+ "longPress": "長按",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 然後 ←",
+ "upThenRight": "↑ 然後 →",
+ "upDown": "↑ 然後 ↓",
+ "leftThenRight": "← 然後 →",
+ "rightThenLeft": "→ 然後 ←",
+ "upLeftThenDown": "↖ 然後 ↓",
+ "upRightThenDown": "↗ 然後 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 然後 ↑",
+ "upThenDownRight": "↑ 然後 ↘",
+ "downThenUpRight": "↓ 然後 ↗",
+ "rightThenUp": "→ 然後 ↑",
+ "rightThenDown": "→ 然後 ↓",
+ "downThenRight": "↓ 然後 →",
+ "downThenLeft": "↓ 然後 ←",
+ "downRightThenUp": "↘ 然後 ↑",
+ "downLeftThenUp": "↙ 然後 ↑",
+ "upLeftThenRight": "↖ 然後 →",
+ "upRightThenLeft": "↗ 然後 ←"
},
"actions": {
- "newConversation": "New conversation",
- "toggleSidebar": "Toggle sidebar",
- "toggleSearch": "Search",
- "toggleTerminal": "Toggle terminal",
- "nextTab": "Next tab",
- "prevTab": "Previous tab",
- "reopenClosedTab": "Reopen closed tab",
- "openFolder": "Open folder",
- "zoomIn": "Zoom in",
- "zoomOut": "Zoom out",
- "zoomReset": "Reset zoom",
- "stopGenerating": "Stop generating",
- "openSettings": "Settings",
- "openTodos": "To-dos",
- "openTodosNew": "New to-do",
- "openAutomations": "Automations",
- "openCanvas": "Canvas",
- "openAgents": "Agents",
- "openSystemAdmin": "System admin",
- "renameConversation": "Rename conversation",
- "openSessionFolder": "Session files",
- "cycleAgent": "Next agent",
- "cycleFavoriteAgent": "Favorite agents"
+ "newConversation": "新增對話",
+ "toggleSidebar": "切換側欄",
+ "toggleSearch": "搜尋",
+ "toggleTerminal": "切換終端機",
+ "nextTab": "下一個分頁",
+ "prevTab": "上一個分頁",
+ "reopenClosedTab": "恢復關閉的分頁",
+ "openFolder": "開啟資料夾",
+ "zoomIn": "放大",
+ "zoomOut": "縮小",
+ "zoomReset": "重設縮放",
+ "stopGenerating": "停止生成",
+ "openSettings": "設定",
+ "openTodos": "待辦任務",
+ "openTodosNew": "新建待辦",
+ "openAutomations": "自動化",
+ "openCanvas": "無限畫布",
+ "openAgents": "智慧代理人",
+ "openSystemAdmin": "系統管理",
+ "renameConversation": "重新命名會話",
+ "openSessionFolder": "會話檔案",
+ "cycleAgent": "下一個代理人",
+ "cycleFavoriteAgent": "常用代理人",
+ "openBallBindings": "手勢綁定",
+ "cycleRunningSessions": "執行中的會話",
+ "cycleRecentSessions": "最近的會話",
+ "deleteCurrentConversation": "刪除當前會話",
+ "openImportSessions": "匯入會話",
+ "togglePinConversation": "置頂/取消置頂",
+ "focusModeSelector": "模式選擇",
+ "togglePlanFullAccess": "Plan/全權限切換",
+ "openCollaboration": "協作"
}
},
"SystemSettings": {
@@ -1185,30 +1201,6 @@
"apiKeyHint": "以 KIRO_API_KEY 傳給 CLI。留空則使用 kiro-cli login 登入的帳號;只有無法用瀏覽器登入的環境(伺服器、Docker)才需要 API Key。",
"saveConfig": "儲存 Kiro 設定"
},
- "trae": {
- "configManagement": "設定管理",
- "configDescription": "TRAE CLI 2.0 僅開放給 TRAE 企業版旗艦版方案的客戶。Codeg 執行你安裝的 traecli,它把登入狀態、技能和 MCP 伺服器儲存在 ~/.trae 中。模型、模式和推理強度不在這裡設定:TRAE CLI 會透過 ACP 回報它們,由輸入框內建的選擇器依工作階段管理。",
- "signInTitle": "登入",
- "signInHint": "在終端機中執行一次下面的命令,用企業 SSO 登入。Codeg 裡的工作階段會沿用這次登入。",
- "copyCommand": "複製命令",
- "commandCopied": "命令已複製",
- "patLabel": "個人存取權杖(選填)",
- "patHint": "適用於無法用瀏覽器登入的機器,例如伺服器或 Docker 部署。Codeg 會以 TRAECLI_PERSONAL_ACCESS_TOKEN 傳給 TRAE CLI,並在每次啟動工作階段時用它登入。留空則使用 traecli login 的登入。",
- "hostLabel": "企業 API 位址(選填)",
- "hostHint": "僅當你的組織在自有網域上部署 TRAE 時填寫。以 TRAECLI_HOST 傳入;留空則使用 TRAE 官方服務。",
- "saveConfig": "儲存 TRAE CLI 設定"
- },
- "commandCode": {
- "configManagement": "設定管理",
- "configDescription": "Codeg 執行 command-code npm 套件提供的 Command Code CLI,它把登入狀態、技能和 MCP 伺服器儲存在 ~/.commandcode 中。模型、模式和推理強度不在這裡設定:Command Code 會透過 ACP 回報它們,由輸入框內建的選擇器依工作階段管理。",
- "signInTitle": "登入",
- "signInHint": "在終端機中執行一次下面的命令,登入你的 Command Code 帳號。Codeg 裡的工作階段會沿用這次登入。",
- "copyCommand": "複製命令",
- "commandCopied": "命令已複製",
- "apiKeyLabel": "API 金鑰(選填)",
- "apiKeyHint": "適用於無法用瀏覽器登入的機器,例如伺服器或 Docker 部署。以 COMMAND_CODE_API_KEY 傳給 Command Code,優先於 command-code login 的登入。留空則使用那次登入。",
- "saveConfig": "儲存 Command Code 設定"
- },
"deepseek": {
"configManagement": "DeepSeek Harness 設定",
"configDescription": "端點與金鑰是 deepseek-acp 啟動時讀取的環境變數。模型與推理等級是工作階段層級的選擇器,在輸入框裡切換。",
@@ -1704,10 +1696,6 @@
"saveAntigravityConfigFailed": "保存 Antigravity 配置失败",
"kiroSaved": "Kiro 設定已儲存",
"saveKiroFailed": "儲存 Kiro 設定失敗",
- "traeSaved": "TRAE CLI 設定已儲存",
- "saveTraeFailed": "儲存 TRAE CLI 設定失敗",
- "commandCodeSaved": "Command Code 設定已儲存",
- "saveCommandCodeFailed": "儲存 Command Code 設定失敗",
"systemAgentAlreadyLatest": "{name} 已是最新版本({version})"
},
"distribution": {
@@ -2479,10 +2467,7 @@
"commits": "提交"
},
"noFolderTitle": "尚無開啟的資料夾",
- "noFolderHint": "開啟一個資料夾後可在此查看",
- "openFullPage": "在完整頁面中開啟",
- "back": "返回",
- "noAutomations": "此專案還沒有自動化"
+ "noFolderHint": "開啟一個資料夾後可在此查看"
},
"windowControls": {
"minimizeWindow": "最小化視窗",
@@ -3381,7 +3366,6 @@
},
"messageInput": {
"askAnything": "請開始輸入...",
- "promptSuggestion": "{suggestion}(按 Tab 填入)",
"removeAttachmentAria": "移除 {name}",
"attachFiles": "附加檔案",
"addActions": "新增",
@@ -3411,10 +3395,6 @@
"searchModelAria": "搜尋模型",
"modelListLabel": "模型",
"recommendedBadge": "推薦",
- "recommendedValue": "推薦:{value}",
- "searchOptions": "搜尋選項...",
- "searchOptionsAria": "搜尋選項",
- "noOptions": "找不到選項",
"noModels": "找不到模型",
"cancel": "取消",
"send": "傳送",
@@ -4027,16 +4007,13 @@
},
"messageNav": {
"title": "訊息導覽",
+ "collapse": "收合訊息導覽",
"loadingEarlier": "正在載入更早的訊息…",
"loadEarlier": "載入更早的訊息",
+ "collapsedSummary": "訊息 {count}",
"fileCount": "{count} 個檔案",
- "subAgentCount": "{count} 個子智能體",
- "showDiff": "展開 {filePath} 的變更",
- "hideDiff": "收合 {filePath} 的變更",
- "openFile": "開啟 {filePath}",
- "collapse": "收合",
- "currentMessage": "目前訊息",
- "scrollToCurrent": "捲動到目前訊息(#{ordinal})"
+ "remove": "移除",
+ "noDiffDataAvailable": "找不到 {filePath} 的差異資料"
},
"replyArtifacts": {
"title": "變更檔案",
@@ -4094,9 +4071,6 @@
"resumeDelegation": "恢復任務 {task}",
"resumeDelegationNoId": "恢復委派任務",
"promptLabel": "指令",
- "ackRecorded": "已記錄到待辦任務",
- "ackNotRecorded": "未記錄到待辦任務",
- "ackNotRecordedWithReason": "未記錄到待辦任務:{reason}",
"verdict": {
"success": "成功",
"needs_review": "待複核",
@@ -4214,18 +4188,6 @@
"stopDeclined": "無法停止該任務,它可能已經結束。",
"stopFailed": "停止任務失敗:{error}"
},
- "remoteControl": {
- "title": "遠端控制已開啟",
- "open": "在瀏覽器中開啟",
- "copy": "複製連結",
- "copied": "已複製",
- "qr": "QR 碼",
- "qrLabel": "本會話遠端控制連結的 QR 碼",
- "qrHint": "用手機掃描,在 Claude App 或 claude.ai/code 上繼續本會話。",
- "noUrl": "Claude Code 沒有傳回本會話的連結",
- "turnOff": "關閉",
- "turnOffBusy": "Claude 完成目前工作後可用"
- },
"proposedPlan": {
"title": "計劃提案",
"planning": "規劃中…"
@@ -7433,44 +7395,62 @@
"renameConversation": "重新命名會話",
"openSessionFolder": "會話檔案",
"cycleAgent": "下一個代理人",
- "cycleFavoriteAgent": "常用代理人"
+ "cycleFavoriteAgent": "常用代理人",
+ "openBallBindings": "手勢綁定",
+ "cycleRunningSessions": "執行中的會話",
+ "cycleRecentSessions": "最近的會話",
+ "deleteCurrentConversation": "刪除當前會話",
+ "openImportSessions": "匯入會話",
+ "togglePinConversation": "置頂/取消置頂",
+ "focusModeSelector": "模式選擇",
+ "togglePlanFullAccess": "Plan/全權限切換",
+ "openCollaboration": "協作"
},
"gestures": {
"tap": "單擊",
"doubleTap": "雙擊",
"longPress": "長按",
- "left": "左滑",
- "right": "右滑",
- "up": "上滑",
- "upLeft": "左上滑",
- "upRight": "右上滑",
- "upThenLeft": "上滑後左滑",
- "upThenRight": "上滑後右滑",
- "upDown": "上滑後下滑",
- "leftThenRight": "左滑後右滑",
- "rightThenLeft": "右滑後左滑",
- "upLeftThenDown": "左上滑後下滑",
- "upRightThenDown": "右上滑後下滑",
- "down": "下滑",
- "downLeft": "左下",
- "downRight": "右下",
- "downUp": "下再上",
- "upThenDownRight": "上再右下",
- "downThenUpRight": "下再右上",
- "rightThenUp": "右再上",
- "rightThenDown": "右再下",
- "downThenRight": "下再右",
- "downThenLeft": "下再左",
- "downRightThenUp": "右下再上",
- "downLeftThenUp": "左下再上",
- "upLeftThenRight": "左上再右",
- "upRightThenLeft": "右上再左"
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 然後 ←",
+ "upThenRight": "↑ 然後 →",
+ "upDown": "↑ 然後 ↓",
+ "leftThenRight": "← 然後 →",
+ "rightThenLeft": "→ 然後 ←",
+ "upLeftThenDown": "↖ 然後 ↓",
+ "upRightThenDown": "↗ 然後 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 然後 ↑",
+ "upThenDownRight": "↑ 然後 ↘",
+ "downThenUpRight": "↓ 然後 ↗",
+ "rightThenUp": "→ 然後 ↑",
+ "rightThenDown": "→ 然後 ↓",
+ "downThenRight": "↓ 然後 →",
+ "downThenLeft": "↓ 然後 ←",
+ "downRightThenUp": "↘ 然後 ↑",
+ "downLeftThenUp": "↙ 然後 ↑",
+ "upLeftThenRight": "↖ 然後 →",
+ "upRightThenLeft": "↗ 然後 ←"
},
"favoriteAgentsEmpty": "暫無可用代理人",
"toasts": {
"renameNeedsSavedSession": "重新命名只對已儲存的會話生效——先發一則訊息。",
"sessionFolderNeedsWorkspace": "請先開啟一個工作區資料夾。",
- "cycleNeedsMoreAgents": "可用智慧型代理只有一個,無可切換。"
- }
+ "cycleNeedsMoreAgents": "可用智慧型代理只有一個,無可切換。",
+ "noOtherRunning": "沒有其他執行中的會話",
+ "noOtherRecent": "沒有其他最近的會話",
+ "noPlanMode": "當前智能體沒有 Plan 模式",
+ "pinToggled": "置頂狀態已更新",
+ "noRunningSession": "還沒有執行中的會話",
+ "noModesAvailable": "該智慧代理沒有可用模式。",
+ "noSwitchTarget": "沒有可切換的模式(未找到 Plan 或完整存取模式)。"
+ },
+ "recentSessionDepth": "最近會話切換深度",
+ "bindingCleared": "未綁定"
}
-}
+}
\ No newline at end of file
diff --git a/src/lib/floating-ball-gestures.ts b/src/lib/floating-ball-gestures.ts
index 30da2f4ac7..85ea893dae 100644
--- a/src/lib/floating-ball-gestures.ts
+++ b/src/lib/floating-ball-gestures.ts
@@ -75,6 +75,15 @@ export type FloatingBallAction =
| "openSessionFolder"
| "cycleAgent"
| "cycleFavoriteAgent"
+ | "openBallBindings"
+ | "cycleRunningSessions"
+ | "cycleRecentSessions"
+ | "deleteCurrentConversation"
+ | "openImportSessions"
+ | "togglePinConversation"
+ | "focusModeSelector"
+ | "togglePlanFullAccess"
+ | "openCollaboration"
export const FLOATING_BALL_GESTURES: readonly FloatingBallGesture[] = [
"tap",
diff --git a/src/lib/floating-ball-session-events.test.ts b/src/lib/floating-ball-session-events.test.ts
new file mode 100644
index 0000000000..ecea63d6ef
--- /dev/null
+++ b/src/lib/floating-ball-session-events.test.ts
@@ -0,0 +1,52 @@
+import { describe, expect, vi, beforeEach } from "vitest"
+import {
+ requestDeleteConversation,
+ requestFocusModeSelector,
+ requestTogglePlanFull,
+ eventMatchesConversation,
+ DELETE_CONVERSATION_EVENT,
+ FOCUS_MODE_SELECTOR_EVENT,
+ TOGGLE_PLAN_FULL_EVENT,
+} from "./floating-ball-session-events"
+
+describe("floating-ball-session-events", () => {
+ beforeEach(() => {
+ vi.restoreAllMocks()
+ })
+
+ it("dispatch carries the conversation id on the right event type", () => {
+ const seen: Array<{ type: string; id: number | null }> = []
+ const onDelete = (e: Event) =>
+ seen.push({
+ type: e.type,
+ id: (e as CustomEvent<{ conversationId: number | null }>).detail
+ .conversationId,
+ })
+ window.addEventListener(DELETE_CONVERSATION_EVENT, onDelete)
+ window.addEventListener(FOCUS_MODE_SELECTOR_EVENT, onDelete)
+ window.addEventListener(TOGGLE_PLAN_FULL_EVENT, onDelete)
+
+ requestDeleteConversation(7)
+ requestFocusModeSelector(null)
+ requestTogglePlanFull(9)
+
+ window.removeEventListener(DELETE_CONVERSATION_EVENT, onDelete)
+ window.removeEventListener(FOCUS_MODE_SELECTOR_EVENT, onDelete)
+ window.removeEventListener(TOGGLE_PLAN_FULL_EVENT, onDelete)
+
+ expect(seen).toEqual([
+ { type: DELETE_CONVERSATION_EVENT, id: 7 },
+ { type: FOCUS_MODE_SELECTOR_EVENT, id: null },
+ { type: TOGGLE_PLAN_FULL_EVENT, id: 9 },
+ ])
+ })
+
+ it("eventMatchesConversation filters by id (multi-tab safety)", () => {
+ expect(eventMatchesConversation({ conversationId: 3 }, 3)).toBe(true)
+ expect(eventMatchesConversation({ conversationId: 3 }, 4)).toBe(false)
+ // Draft (null) events only match draft instances.
+ expect(eventMatchesConversation({ conversationId: null }, null)).toBe(true)
+ expect(eventMatchesConversation({ conversationId: null }, 3)).toBe(false)
+ expect(eventMatchesConversation(undefined, 3)).toBe(false)
+ })
+})
diff --git a/src/lib/floating-ball-session-events.ts b/src/lib/floating-ball-session-events.ts
new file mode 100644
index 0000000000..a72999d588
--- /dev/null
+++ b/src/lib/floating-ball-session-events.ts
@@ -0,0 +1,47 @@
+/**
+ * Floating-ball hand-off events for actions that must run inside a mounted
+ * conversation view (which owns the mode selector, pin state and the delete
+ * confirm dialog). Each event carries the DB conversation id and each
+ * per-tab instance compares it against its own — a tab whose conversation
+ * does not match ignores the event (multi-tab safe, same idiom as
+ * rename-conversation-events but synchronous).
+ */
+
+export const DELETE_CONVERSATION_EVENT = "codeg:fb-delete-conversation"
+export const FOCUS_MODE_SELECTOR_EVENT = "codeg:fb-focus-mode-selector"
+export const TOGGLE_PLAN_FULL_EVENT = "codeg:fb-toggle-plan-full"
+
+export interface FloatingBallSessionDetail {
+ conversationId: number | null
+}
+
+function dispatch(type: string, conversationId: number | null) {
+ window.dispatchEvent(
+ new CustomEvent(type, {
+ detail: { conversationId } satisfies FloatingBallSessionDetail,
+ })
+ )
+}
+
+/** Open the delete confirmation for the current session (header-owned UI). */
+export function requestDeleteConversation(conversationId: number | null) {
+ dispatch(DELETE_CONVERSATION_EVENT, conversationId)
+}
+
+/** Focus/open the composer's inline mode selector on the active tab. */
+export function requestFocusModeSelector(conversationId: number | null) {
+ dispatch(FOCUS_MODE_SELECTOR_EVENT, conversationId)
+}
+
+/** Switch the active session between Plan and full-access mode. */
+export function requestTogglePlanFull(conversationId: number | null) {
+ dispatch(TOGGLE_PLAN_FULL_EVENT, conversationId)
+}
+
+/** True when the event targets this instance's conversation (null = drafts). */
+export function eventMatchesConversation(
+ detail: FloatingBallSessionDetail | undefined,
+ conversationId: number | null
+): boolean {
+ return detail?.conversationId === conversationId
+}
diff --git a/src/lib/recent-sessions-prefs.test.ts b/src/lib/recent-sessions-prefs.test.ts
new file mode 100644
index 0000000000..a4e59ba6c5
--- /dev/null
+++ b/src/lib/recent-sessions-prefs.test.ts
@@ -0,0 +1,77 @@
+import { describe, expect, beforeEach } from "vitest"
+import {
+ rememberRecentConversation,
+ forgetRecentConversation,
+ nextRecentConversation,
+ readRecentSessionDepth,
+ writeRecentSessionDepth,
+ DEFAULT_RECENT_SESSION_DEPTH,
+} from "./recent-sessions-prefs"
+
+describe("recent-sessions-prefs", () => {
+ beforeEach(() => {
+ window.localStorage.clear()
+ })
+
+ it("rememberRecentConversation dedupes and puts most recent first", () => {
+ rememberRecentConversation(1)
+ rememberRecentConversation(2)
+ rememberRecentConversation(1)
+ expect(nextRecentConversation(null, 4, () => true)).toBe(1)
+ // After re-remembering 1, the next candidate (not active) is 2.
+ rememberRecentConversation(1)
+ expect(nextRecentConversation(1, 4, () => true)).toBe(2)
+ })
+
+ it("caps the queue at 8 entries", () => {
+ for (let i = 1; i <= 12; i++) rememberRecentConversation(i)
+ // Only ids 5..12 survive.
+ for (let i = 1; i <= 4; i++) {
+ expect(nextRecentConversation(null, 8, (id) => id === i)).toBeNull()
+ }
+ expect(nextRecentConversation(null, 8, (id) => id === 5)).toBe(5)
+ })
+
+ it("nextRecentConversation respects depth - 1 candidates", () => {
+ rememberRecentConversation(1)
+ rememberRecentConversation(2)
+ rememberRecentConversation(3)
+ // Queue is [3,2,1]. Depth 2 → one candidate (3). Excluding active 3 → 2.
+ expect(nextRecentConversation(3, 2, () => true)).toBe(2)
+ // Depth 4 → candidates [3,2,1]; excluding active 2 → first is 3.
+ expect(nextRecentConversation(2, 4, () => true)).toBe(3)
+ })
+
+ it("nextRecentConversation filters unavailable ids", () => {
+ rememberRecentConversation(1)
+ rememberRecentConversation(2)
+ expect(nextRecentConversation(null, 4, (id) => id !== 2)).toBe(1)
+ expect(nextRecentConversation(null, 4, () => false)).toBeNull()
+ })
+
+ it("forgetRecentConversation removes a deleted conversation", () => {
+ rememberRecentConversation(1)
+ rememberRecentConversation(2)
+ forgetRecentConversation(1)
+ expect(nextRecentConversation(2, 4, () => true)).toBeNull()
+ expect(nextRecentConversation(1, 4, () => true)).toBe(2)
+ })
+
+ it("depth defaults to 2 and only accepts 3/4 overrides", () => {
+ expect(readRecentSessionDepth()).toBe(DEFAULT_RECENT_SESSION_DEPTH)
+ writeRecentSessionDepth(4)
+ expect(readRecentSessionDepth()).toBe(4)
+ writeRecentSessionDepth(3)
+ expect(readRecentSessionDepth()).toBe(3)
+ })
+
+ it("survives corrupted storage", () => {
+ window.localStorage.setItem("codeg:recent-conversations", "not-json{")
+ expect(nextRecentConversation(null, 4, () => true)).toBeNull()
+ window.localStorage.setItem(
+ "codeg:recent-conversations",
+ JSON.stringify(["a", 5, null, 7])
+ )
+ expect(nextRecentConversation(null, 4, () => true)).toBe(5)
+ })
+})
diff --git a/src/lib/recent-sessions-prefs.ts b/src/lib/recent-sessions-prefs.ts
new file mode 100644
index 0000000000..2b48dbe5ad
--- /dev/null
+++ b/src/lib/recent-sessions-prefs.ts
@@ -0,0 +1,92 @@
+/**
+ * "Recent sessions" LRU queue + switch-depth preference, backing the floating
+ * ball's cycle-recent-sessions gesture.
+ *
+ * The queue lives in localStorage (shared across windows of the same origin)
+ * and stores conversationIds only; consumers must filter to conversations
+ * their own window can actually open. Depth is 2-4 (default 2): with depth 2
+ * the gesture toggles between the two most recently opened conversations.
+ */
+const STORAGE_KEY_RECENT_CONVERSATIONS = "codeg:recent-conversations"
+const STORAGE_KEY_RECENT_SESSION_DEPTH = "codeg:recent-session-depth"
+
+/** Queue holds more than the max depth so switching survives a bit of drift. */
+const QUEUE_CAPACITY = 8
+export const MIN_RECENT_SESSION_DEPTH = 2
+export const MAX_RECENT_SESSION_DEPTH = 4
+export const DEFAULT_RECENT_SESSION_DEPTH = 2
+
+export type RecentSessionDepth = 2 | 3 | 4
+
+function readQueue(): number[] {
+ if (typeof window === "undefined") return []
+ try {
+ const raw = window.localStorage.getItem(STORAGE_KEY_RECENT_CONVERSATIONS)
+ if (!raw) return []
+ const parsed: unknown = JSON.parse(raw)
+ if (!Array.isArray(parsed)) return []
+ return parsed.filter(
+ (id): id is number => typeof id === "number" && Number.isFinite(id)
+ )
+ } catch {
+ return []
+ }
+}
+
+function writeQueue(queue: number[]): void {
+ if (typeof window === "undefined") return
+ try {
+ window.localStorage.setItem(
+ STORAGE_KEY_RECENT_CONVERSATIONS,
+ JSON.stringify(queue.slice(0, QUEUE_CAPACITY))
+ )
+ } catch {
+ // Storage full or unavailable: cycling just becomes a no-op, acceptable.
+ }
+}
+
+/** Push a conversation as "just opened", deduped, most-recent first. */
+export function rememberRecentConversation(id: number): void {
+ const next = [id, ...readQueue().filter((v) => v !== id)]
+ writeQueue(next)
+}
+
+/** Drop a deleted conversation so cycling never lands on it. */
+export function forgetRecentConversation(id: number): void {
+ const next = readQueue().filter((v) => v !== id)
+ if (next.length !== readQueue().length) writeQueue(next)
+}
+
+/**
+ * Pick the next conversation to switch to: the most recent entry that isn't
+ * the active one, within the configured depth window. Returns null when there
+ * is nothing to switch to. Moving the picked id to the front is what makes
+ * repeated gestures toggle between two sessions at depth 2.
+ */
+export function nextRecentConversation(
+ activeId: number | null,
+ depth: number,
+ isAvailable: (id: number) => boolean
+): number | null {
+ const candidates = readQueue()
+ .filter((id) => id !== activeId && isAvailable(id))
+ .slice(0, Math.max(0, depth - 1))
+ return candidates.length > 0 ? candidates[0] : null
+}
+
+export function readRecentSessionDepth(): RecentSessionDepth {
+ if (typeof window === "undefined") return DEFAULT_RECENT_SESSION_DEPTH
+ const raw = window.localStorage.getItem(STORAGE_KEY_RECENT_SESSION_DEPTH)
+ return raw === "3" || raw === "4"
+ ? (Number(raw) as RecentSessionDepth)
+ : DEFAULT_RECENT_SESSION_DEPTH
+}
+
+export function writeRecentSessionDepth(depth: RecentSessionDepth): void {
+ if (typeof window === "undefined") return
+ try {
+ window.localStorage.setItem(STORAGE_KEY_RECENT_SESSION_DEPTH, String(depth))
+ } catch {
+ // Unavailable storage: the selector will read the default back.
+ }
+}
diff --git a/src/stores/tab-store.ts b/src/stores/tab-store.ts
index ba806fe86b..6cb2a2cc58 100644
--- a/src/stores/tab-store.ts
+++ b/src/stores/tab-store.ts
@@ -36,6 +36,7 @@ import {
sweepOrphanDraftKeys,
} from "@/lib/message-input-draft"
import { discardAskSelectionPrompts } from "@/lib/ask-selection-handoff"
+import { rememberRecentConversation } from "@/lib/recent-sessions-prefs"
import {
batchCloseSlots,
pushClosedTab,
@@ -1056,6 +1057,13 @@ function focusTab(tabId: string) {
if (useTabStore.getState().activeTabId !== tabId) {
useTabStore.setState({ activeTabId: tabId })
}
+ // Every activation path funnels through here, so this is the one place the
+ // floating ball's "recent sessions" LRU needs to record a conversation as
+ // "just opened" (bound tabs only; drafts have no DB row yet).
+ const tab = useTabStore.getState().rawTabs.find((t) => t.id === tabId)
+ if (tab?.conversationId != null) {
+ rememberRecentConversation(tab.conversationId)
+ }
applyGroupInvariants()
}
@@ -2101,6 +2109,11 @@ export const useTabStore = create()((set, get) => ({
? prevState.activeTabId
: (boundTab?.id ?? nextTabs[0]?.id ?? null),
})
+ // A draft becomes a real session the first time it persists a DB row —
+ // that is its "first open" for the recent-sessions LRU.
+ if (conversationId != null) {
+ rememberRecentConversation(conversationId)
+ }
recomputeTabs()
},
From dc9e1e4a2e36a49cb25817815e9de78aa056e6df Mon Sep 17 00:00:00 2001
From: fengx
Date: Sun, 18 Oct 2026 16:07:30 +0800
Subject: [PATCH 09/18] =?UTF-8?q?chore(i18n):=20rebuild=20locale=20files?=
=?UTF-8?q?=20on=20upstream=20base=20=E2=80=94=20floating-ball=20sections?=
=?UTF-8?q?=20merged,=20upstream's=20new=20keys=20kept?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/i18n/messages/ar.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/de.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/en.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/es.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/fr.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/ja.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/ko.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/pt.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/zh-CN.json | 183 +++++++++++++++++++++-------------
src/i18n/messages/zh-TW.json | 183 +++++++++++++++++++++-------------
src/lib/default-mode-prefs.ts | 32 ++++++
11 files changed, 1182 insertions(+), 680 deletions(-)
create mode 100644 src/lib/default-mode-prefs.ts
diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json
index a557656ba3..30a1b5f8e2 100644
--- a/src/i18n/messages/ar.json
+++ b/src/i18n/messages/ar.json
@@ -181,13 +181,6 @@
"sectionDescription": "حركات الطي/التوسيع واستدعاءات الأدوات وحالة العمل داخل منطقة المحادثة، إضافةً إلى التمرير السلس. عند الإيقاف تتحدّث الواجهة فورًا. تستمر مؤشرات التحميل في الدوران.",
"enable": "تفعيل حركات المحادثة"
},
- "messageNav": {
- "sectionTitle": "مستكشف الرسائل",
- "sectionDescription": "موضع مستكشف رسائل المحادثة. عند اختيار أسفل اليمين يصبح بطاقة مُدمجة بسطر واحد لكل رسالة مستخدم فوق حقل الإدخال.",
- "positionStart": "أعلى اليسار (افتراضي)",
- "positionBottomEnd": "أسفل اليمين (مُدمج)",
- "hint": "تبقى لوحتا الخطة والوكلاء الفرعيين في أعلى اليسار في كل الأحوال."
- },
"chatWidth": {
"sectionTitle": "عرض المحادثة",
"sectionDescription": "أقصى عرض لعمود المحادثة ومربع الإدخال. يمكنك أيضًا سحب حافتي منطقة المحادثة لضبطه.",
@@ -247,54 +240,6 @@
"credit": "الصور من wallhaven.cc · محتوى آمن فقط"
}
},
- "floatingBall": {
- "sectionTitle": "الكرة العائمة",
- "sectionDescription": "كرة قابلة للسحب فوق مساحة العمل تحوّل السحب إلى اختصارات، مصممة للهاتف حيث لا توجد لوحة مفاتيح.",
- "enable": "إظهار الكرة العائمة",
- "hint": "اسحب للتحريك، اسحب بسرعة لإيماءة، اضغط مطوّلاً للوحة وقائمة الإيماءات.",
- "resetPosition": "إعادة تعيين الموضع",
- "ballSize": "حجم الكرة",
- "sizeSmall": "صغير",
- "sizeMedium": "متوسط",
- "sizeLarge": "كبير",
- "gestureBindings": "ربط الإيماءات",
- "bindingCleared": "غير مربوط",
- "favoriteAgents": "الوكلاء المفضلون",
- "favoriteAgentsHint": "اختر 2-3 وكلاء للتنقل بينهم بإيماءة المفضلين.",
- "favoriteAgentsEmpty": "لا يوجد وكلاء متاحون",
- "panelTitle": "إجراءات سريعة"
- },
- "gestures": {
- "tap": "نقرة",
- "doubleTap": "نقرة مزدوجة",
- "longPress": "ضغط مطول",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ ثم ←",
- "upThenRight": "↑ ثم →",
- "upDown": "↑ ثم ↓",
- "leftThenRight": "← ثم →",
- "rightThenLeft": "→ ثم ←",
- "upLeftThenDown": "↖ ثم ↓",
- "upRightThenDown": "↗ ثم ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ ثم ↑",
- "upThenDownRight": "↑ ثم ↘",
- "downThenUpRight": "↓ ثم ↗",
- "rightThenUp": "→ ثم ↑",
- "rightThenDown": "→ ثم ↓",
- "downThenRight": "↓ ثم →",
- "downThenLeft": "↓ ثم ←",
- "downRightThenUp": "↘ ثم ↑",
- "downLeftThenUp": "↙ ثم ↑",
- "upLeftThenRight": "↖ ثم →",
- "upRightThenLeft": "↗ ثم ←"
- },
"actions": {
"newConversation": "محادثة جديدة",
"toggleSidebar": "تبديل الشريط الجانبي",
@@ -328,6 +273,54 @@
"focusModeSelector": "محدد الوضع",
"togglePlanFullAccess": "خطة / وصول كامل",
"openCollaboration": "التعاون"
+ },
+ "gestures": {
+ "tap": "نقرة",
+ "doubleTap": "نقرة مزدوجة",
+ "longPress": "ضغط مطول",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ ثم ←",
+ "upThenRight": "↑ ثم →",
+ "upDown": "↑ ثم ↓",
+ "leftThenRight": "← ثم →",
+ "rightThenLeft": "→ ثم ←",
+ "upLeftThenDown": "↖ ثم ↓",
+ "upRightThenDown": "↗ ثم ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ ثم ↑",
+ "upThenDownRight": "↑ ثم ↘",
+ "downThenUpRight": "↓ ثم ↗",
+ "rightThenUp": "→ ثم ↑",
+ "rightThenDown": "→ ثم ↓",
+ "downThenRight": "↓ ثم →",
+ "downThenLeft": "↓ ثم ←",
+ "downRightThenUp": "↘ ثم ↑",
+ "downLeftThenUp": "↙ ثم ↑",
+ "upLeftThenRight": "↖ ثم →",
+ "upRightThenLeft": "↗ ثم ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "الكرة العائمة",
+ "sectionDescription": "كرة قابلة للسحب فوق مساحة العمل تحوّل السحب إلى اختصارات، مصممة للهاتف حيث لا توجد لوحة مفاتيح.",
+ "enable": "إظهار الكرة العائمة",
+ "hint": "اسحب للتحريك، اسحب بسرعة لإيماءة، اضغط مطوّلاً للوحة وقائمة الإيماءات.",
+ "resetPosition": "إعادة تعيين الموضع",
+ "ballSize": "حجم الكرة",
+ "sizeSmall": "صغير",
+ "sizeMedium": "متوسط",
+ "sizeLarge": "كبير",
+ "gestureBindings": "ربط الإيماءات",
+ "bindingCleared": "غير مربوط",
+ "favoriteAgents": "الوكلاء المفضلون",
+ "favoriteAgentsHint": "اختر 2-3 وكلاء للتنقل بينهم بإيماءة المفضلين.",
+ "favoriteAgentsEmpty": "لا يوجد وكلاء متاحون",
+ "panelTitle": "إجراءات سريعة"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "يُمرَّر إلى CLI باسم KIRO_API_KEY. اتركه فارغاً لاستخدام الحساب الذي سجلت الدخول به عبر kiro-cli login؛ لا يلزم إلا حيث يتعذر تسجيل الدخول بالمتصفح (الخوادم، Docker).",
"saveConfig": "حفظ إعدادات Kiro"
},
+ "trae": {
+ "configManagement": "إدارة الإعدادات",
+ "configDescription": "يتوفر TRAE CLI 2.0 لعملاء الخطة الرئيسية من TRAE Enterprise فقط. يشغّل Codeg أداة traecli التي ثبّتّها، وهي تحفظ تسجيل الدخول والمهارات وخوادم MCP في ~/.trae. النموذج والوضع ومستوى الاستدلال ليست هنا: يُبلغ عنها TRAE CLI عبر ACP، لذا تديرها محددات المحرّر لكل جلسة.",
+ "signInTitle": "تسجيل الدخول",
+ "signInHint": "شغّل هذا الأمر مرة واحدة في الطرفية لتسجيل الدخول عبر SSO الخاص بمؤسستك. تعيد جلسات Codeg استخدام تسجيل الدخول هذا.",
+ "copyCommand": "نسخ الأمر",
+ "commandCopied": "تم نسخ الأمر",
+ "patLabel": "رمز الوصول الشخصي (اختياري)",
+ "patHint": "للأجهزة التي يتعذر فيها تسجيل الدخول بالمتصفح، مثل الخوادم أو تثبيتات Docker. يمرّره Codeg إلى TRAE CLI باسم TRAECLI_PERSONAL_ACCESS_TOKEN ويسجّل الدخول به عند بدء كل جلسة. اتركه فارغاً لاستخدام تسجيل الدخول من traecli login.",
+ "hostLabel": "عنوان API الخاص بالمؤسسة (اختياري)",
+ "hostHint": "فقط إذا كانت مؤسستك تشغّل TRAE على نطاقها الخاص. يُمرَّر باسم TRAECLI_HOST؛ اتركه فارغاً لاستخدام خدمة TRAE نفسها.",
+ "saveConfig": "حفظ إعدادات TRAE CLI"
+ },
+ "commandCode": {
+ "configManagement": "إدارة الإعدادات",
+ "configDescription": "يشغّل Codeg واجهة Command Code CLI من حزمة npm المسماة command-code، وهي تحفظ تسجيل الدخول والمهارات وخوادم MCP في ~/.commandcode. النموذج والوضع ومستوى الاستدلال ليست هنا: يُبلغ عنها Command Code عبر ACP، لذا تديرها محددات المحرّر لكل جلسة.",
+ "signInTitle": "تسجيل الدخول",
+ "signInHint": "شغّل هذا الأمر مرة واحدة في الطرفية لتسجيل الدخول بحساب Command Code الخاص بك. تعيد جلسات Codeg استخدام تسجيل الدخول هذا.",
+ "copyCommand": "نسخ الأمر",
+ "commandCopied": "تم نسخ الأمر",
+ "apiKeyLabel": "مفتاح API (اختياري)",
+ "apiKeyHint": "للأجهزة التي يتعذر فيها تسجيل الدخول بالمتصفح، مثل الخوادم أو تثبيتات Docker. يُمرَّر إلى Command Code باسم COMMAND_CODE_API_KEY ويتقدّم على تسجيل الدخول من command-code login. اتركه فارغاً لاستخدام تسجيل الدخول ذاك.",
+ "saveConfig": "حفظ إعدادات Command Code"
+ },
"deepseek": {
"configManagement": "إعدادات DeepSeek Harness",
"configDescription": "نقطة النهاية والمفتاح متغيّرا بيئة يقرأهما deepseek-acp عند الإقلاع. أما النموذج ومستوى الاستدلال فمحدِّدان على مستوى الجلسة، ويُختاران من حقل الإدخال.",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "تم حفظ إعدادات Kiro",
"saveKiroFailed": "تعذّر حفظ إعدادات Kiro",
+ "traeSaved": "تم حفظ إعدادات TRAE CLI",
+ "saveTraeFailed": "تعذّر حفظ إعدادات TRAE CLI",
+ "commandCodeSaved": "تم حفظ إعدادات Command Code",
+ "saveCommandCodeFailed": "تعذّر حفظ إعدادات Command Code",
"systemAgentAlreadyLatest": "{name} محدَّث بالفعل ({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "الالتزامات"
},
"noFolderTitle": "لا يوجد مجلد مفتوح",
- "noFolderHint": "افتح مجلدا لعرض محتواه هنا"
+ "noFolderHint": "افتح مجلدا لعرض محتواه هنا",
+ "openFullPage": "فتح في صفحة كاملة",
+ "back": "رجوع",
+ "noAutomations": "لا توجد أتمتة لهذا المشروع بعد"
},
"windowControls": {
"minimizeWindow": "تصغير النافذة",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "اسأل أي شيء...",
+ "promptSuggestion": "{suggestion} (اضغط Tab للاستخدام)",
"removeAttachmentAria": "إزالة {name}",
"attachFiles": "إرفاق ملفات",
"addActions": "إضافة",
@@ -3395,6 +3420,10 @@
"searchModelAria": "البحث عن النماذج",
"modelListLabel": "النماذج",
"recommendedBadge": "موصى به",
+ "recommendedValue": "موصى به: {value}",
+ "searchOptions": "البحث في الخيارات...",
+ "searchOptionsAria": "البحث في الخيارات",
+ "noOptions": "لم يتم العثور على خيارات",
"noModels": "لم يتم العثور على نماذج",
"cancel": "إلغاء",
"send": "إرسال",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "تنقل الرسائل",
- "collapse": "طي تنقل الرسائل",
"loadingEarlier": "جارٍ تحميل الرسائل السابقة…",
"loadEarlier": "تحميل الرسائل السابقة",
- "collapsedSummary": "الرسائل {count}",
"fileCount": "{count, plural, one {# ملف} other {# ملفات}}",
- "remove": "إزالة",
- "noDiffDataAvailable": "لا توجد بيانات diff متاحة لـ {filePath}"
+ "subAgentCount": "{count, plural, one {# وكيل فرعي} other {# وكلاء فرعيين}}",
+ "showDiff": "إظهار تغييرات {filePath}",
+ "hideDiff": "إخفاء تغييرات {filePath}",
+ "openFile": "فتح {filePath}",
+ "collapse": "طي",
+ "currentMessage": "الرسالة الحالية",
+ "scrollToCurrent": "التمرير إلى الرسالة الحالية (#{ordinal})"
},
"replyArtifacts": {
"title": "الملفات المتغيرة",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "استئناف المهمة {task}",
"resumeDelegationNoId": "استئناف مهمة مفوضة",
"promptLabel": "التعليمات",
+ "ackRecorded": "سُجِّل في مهمة العمل",
+ "ackNotRecorded": "لم يُسجَّل في مهمة العمل",
+ "ackNotRecordedWithReason": "لم يُسجَّل في مهمة العمل: {reason}",
"verdict": {
"success": "ناجحة",
"needs_review": "بحاجة إلى مراجعة",
@@ -4188,6 +4223,18 @@
"stopDeclined": "تعذّر إيقاف هذه المهمة، ربما تكون قد انتهت بالفعل.",
"stopFailed": "فشل إيقاف المهمة: {error}"
},
+ "remoteControl": {
+ "title": "التحكم عن بُعد مُفعّل",
+ "open": "فتح في المتصفح",
+ "copy": "نسخ الرابط",
+ "copied": "تم النسخ",
+ "qr": "رمز QR",
+ "qrLabel": "رمز QR لرابط التحكم عن بُعد لهذه الجلسة",
+ "qrHint": "امسحه بهاتفك لمتابعة هذه الجلسة في تطبيق Claude أو على claude.ai/code.",
+ "noUrl": "لم يُرجع Claude Code رابطًا لهذه الجلسة",
+ "turnOff": "إيقاف",
+ "turnOffBusy": "متاح بعد أن ينتهي Claude"
+ },
"proposedPlan": {
"title": "الخطة المقترحة",
"planning": "جارٍ التخطيط…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "الكرة العائمة",
- "panelTitle": "إجراءات سريعة",
- "settingsTitle": "الكرة العائمة",
- "close": "إغلاق",
- "resetPosition": "إعادة تعيين الموضع",
- "cheatSheetTitle": "الإيماءات",
- "hint": "اسحب الكرة لتحريكها. السحب السريع يشغّل إيماءة، والضغط المطوّل يفتح هذه اللوحة.",
"actions": {
"newConversation": "محادثة جديدة",
"toggleSidebar": "تبديل الشريط الجانبي",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ ثم →",
"upRightThenLeft": "↗ ثم ←"
},
- "favoriteAgentsEmpty": "لا يوجد وكلاء متاحون",
"toasts": {
"renameNeedsSavedSession": "إعادة التسمية تعمل على الجلسات المحفوظة فقط — أرسل رسالة أولاً.",
"sessionFolderNeedsWorkspace": "افتح مجلد مساحة العمل أولاً.",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "لا يوفر هذا الوكيل أي أوضاع.",
"noSwitchTarget": "لا يوجد وضع للتبديل إليه (لم يتم العثور على وضع Plan أو الوصول الكامل)."
},
+ "label": "الكرة العائمة",
+ "panelTitle": "إجراءات سريعة",
+ "settingsTitle": "الكرة العائمة",
+ "close": "إغلاق",
+ "resetPosition": "إعادة تعيين الموضع",
+ "cheatSheetTitle": "الإيماءات",
+ "hint": "اسحب الكرة لتحريكها. السحب السريع يشغّل إيماءة، والضغط المطوّل يفتح هذه اللوحة.",
+ "favoriteAgentsEmpty": "لا يوجد وكلاء متاحون",
"recentSessionDepth": "عمق تبديل الجلسات الأخيرة",
"bindingCleared": "غير مربوط"
}
diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json
index cf581c7fb1..e7fbca7e6b 100644
--- a/src/i18n/messages/de.json
+++ b/src/i18n/messages/de.json
@@ -181,13 +181,6 @@
"sectionDescription": "Animationen für Ein-/Ausklappen, Tool-Aufrufe und Arbeitsstatus im Unterhaltungsbereich sowie sanftes Scrollen. Wenn deaktiviert, werden Änderungen sofort angezeigt. Ladeanzeigen drehen sich weiterhin.",
"enable": "Chat-Animationen aktivieren"
},
- "messageNav": {
- "sectionTitle": "Nachrichten-Navigator",
- "sectionDescription": "Position des Nachrichten-Navigators. Unten rechts wird er zu einer kompakten Karte mit einer Zeile pro Nutzernachricht über dem Eingabefeld.",
- "positionStart": "Oben links (Standard)",
- "positionBottomEnd": "Unten rechts (kompakt)",
- "hint": "Plan- und Subagenten-Panels bleiben in beiden Fällen oben links."
- },
"chatWidth": {
"sectionTitle": "Chat-Breite",
"sectionDescription": "Maximale Breite der Unterhaltungsspalte und des Eingabefelds. Sie lässt sich auch durch Ziehen der Chat-Ränder anpassen.",
@@ -247,54 +240,6 @@
"credit": "Bilder von wallhaven.cc · nur SFW"
}
},
- "floatingBall": {
- "sectionTitle": "Schwebekugel",
- "sectionDescription": "Eine verschiebbare Kugel über dem Arbeitsbereich, die Wischgesten in Tastenkürzel verwandelt – gedacht für das Telefon ohne Tastatur.",
- "enable": "Schwebekugel anzeigen",
- "hint": "Ziehen zum Verschieben, schnelles Wischen für eine Geste, langes Drücken für Panel und Gestenübersicht.",
- "resetPosition": "Position zurücksetzen",
- "ballSize": "Kugelgröße",
- "sizeSmall": "Klein",
- "sizeMedium": "Mittel",
- "sizeLarge": "Groß",
- "gestureBindings": "Gestenzuordnung",
- "bindingCleared": "Nicht zugewiesen",
- "favoriteAgents": "Favoriten-Agenten",
- "favoriteAgentsHint": "Wähle 2-3 Agenten, um sie mit dem Favoriten-Gest zu durchlaufen.",
- "favoriteAgentsEmpty": "Keine Agenten verfügbar",
- "panelTitle": "Schnellaktionen"
- },
- "gestures": {
- "tap": "Tippen",
- "doubleTap": "Doppelt tippen",
- "longPress": "Lange drücken",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ dann ←",
- "upThenRight": "↑ dann →",
- "upDown": "↑ dann ↓",
- "leftThenRight": "← dann →",
- "rightThenLeft": "→ dann ←",
- "upLeftThenDown": "↖ dann ↓",
- "upRightThenDown": "↗ dann ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ dann ↑",
- "upThenDownRight": "↑ dann ↘",
- "downThenUpRight": "↓ dann ↗",
- "rightThenUp": "→ dann ↑",
- "rightThenDown": "→ dann ↓",
- "downThenRight": "↓ dann →",
- "downThenLeft": "↓ dann ←",
- "downRightThenUp": "↘ dann ↑",
- "downLeftThenUp": "↙ dann ↑",
- "upLeftThenRight": "↖ dann →",
- "upRightThenLeft": "↗ dann ←"
- },
"actions": {
"newConversation": "Neue Unterhaltung",
"toggleSidebar": "Seitenleiste umschalten",
@@ -328,6 +273,54 @@
"focusModeSelector": "Modus-Auswahl",
"togglePlanFullAccess": "Plan / Vollzugriff",
"openCollaboration": "Kollaboration"
+ },
+ "gestures": {
+ "tap": "Tippen",
+ "doubleTap": "Doppelt tippen",
+ "longPress": "Lange drücken",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ dann ←",
+ "upThenRight": "↑ dann →",
+ "upDown": "↑ dann ↓",
+ "leftThenRight": "← dann →",
+ "rightThenLeft": "→ dann ←",
+ "upLeftThenDown": "↖ dann ↓",
+ "upRightThenDown": "↗ dann ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ dann ↑",
+ "upThenDownRight": "↑ dann ↘",
+ "downThenUpRight": "↓ dann ↗",
+ "rightThenUp": "→ dann ↑",
+ "rightThenDown": "→ dann ↓",
+ "downThenRight": "↓ dann →",
+ "downThenLeft": "↓ dann ←",
+ "downRightThenUp": "↘ dann ↑",
+ "downLeftThenUp": "↙ dann ↑",
+ "upLeftThenRight": "↖ dann →",
+ "upRightThenLeft": "↗ dann ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "Schwebekugel",
+ "sectionDescription": "Eine verschiebbare Kugel über dem Arbeitsbereich, die Wischgesten in Tastenkürzel verwandelt – gedacht für das Telefon ohne Tastatur.",
+ "enable": "Schwebekugel anzeigen",
+ "hint": "Ziehen zum Verschieben, schnelles Wischen für eine Geste, langes Drücken für Panel und Gestenübersicht.",
+ "resetPosition": "Position zurücksetzen",
+ "ballSize": "Kugelgröße",
+ "sizeSmall": "Klein",
+ "sizeMedium": "Mittel",
+ "sizeLarge": "Groß",
+ "gestureBindings": "Gestenzuordnung",
+ "bindingCleared": "Nicht zugewiesen",
+ "favoriteAgents": "Favoriten-Agenten",
+ "favoriteAgentsHint": "Wähle 2-3 Agenten, um sie mit dem Favoriten-Gest zu durchlaufen.",
+ "favoriteAgentsEmpty": "Keine Agenten verfügbar",
+ "panelTitle": "Schnellaktionen"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "Wird der CLI als KIRO_API_KEY übergeben. Leer lassen, um das per kiro-cli login angemeldete Konto zu nutzen; nur nötig, wo keine Browser-Anmeldung möglich ist (Server, Docker).",
"saveConfig": "Kiro-Konfiguration speichern"
},
+ "trae": {
+ "configManagement": "Konfiguration",
+ "configDescription": "TRAE CLI 2.0 steht nur Kunden des Flaggschiff-Tarifs von TRAE Enterprise zur Verfügung. Codeg startet das von dir installierte traecli, das Anmeldung, Skills und MCP-Server in ~/.trae speichert. Modell, Modus und Denkaufwand stehen nicht hier: TRAE CLI meldet sie über ACP, daher verwalten die Auswahlfelder im Eingabebereich sie pro Sitzung.",
+ "signInTitle": "Anmelden",
+ "signInHint": "Führe dies einmal in einem Terminal aus, um dich mit dem SSO deines Unternehmens anzumelden. Sitzungen in Codeg verwenden diese Anmeldung wieder.",
+ "copyCommand": "Befehl kopieren",
+ "commandCopied": "Befehl kopiert",
+ "patLabel": "Persönliches Zugriffstoken (optional)",
+ "patHint": "Für Rechner, auf denen keine Browser-Anmeldung möglich ist, etwa Server oder Docker-Installationen. Codeg übergibt es TRAE CLI als TRAECLI_PERSONAL_ACCESS_TOKEN und meldet sich bei jedem Sitzungsstart damit an. Leer lassen, um die Anmeldung aus traecli login zu nutzen.",
+ "hostLabel": "Enterprise-API-URL (optional)",
+ "hostHint": "Nur wenn deine Organisation TRAE unter einer eigenen Domain betreibt. Wird als TRAECLI_HOST übergeben; leer lassen für den Dienst von TRAE.",
+ "saveConfig": "TRAE CLI-Konfiguration speichern"
+ },
+ "commandCode": {
+ "configManagement": "Konfiguration",
+ "configDescription": "Codeg startet die Command Code CLI aus dem npm-Paket command-code, die Anmeldung, Skills und MCP-Server in ~/.commandcode speichert. Modell, Modus und Denkaufwand stehen nicht hier: Command Code meldet sie über ACP, daher verwalten die Auswahlfelder im Eingabebereich sie pro Sitzung.",
+ "signInTitle": "Anmelden",
+ "signInHint": "Führe dies einmal in einem Terminal aus, um dich mit deinem Command Code-Konto anzumelden. Sitzungen in Codeg verwenden diese Anmeldung wieder.",
+ "copyCommand": "Befehl kopieren",
+ "commandCopied": "Befehl kopiert",
+ "apiKeyLabel": "API-Schlüssel (optional)",
+ "apiKeyHint": "Für Rechner, auf denen keine Browser-Anmeldung möglich ist, etwa Server oder Docker-Installationen. Wird Command Code als COMMAND_CODE_API_KEY übergeben und hat Vorrang vor der Anmeldung aus command-code login. Leer lassen, um diese Anmeldung zu nutzen.",
+ "saveConfig": "Command Code-Konfiguration speichern"
+ },
"deepseek": {
"configManagement": "DeepSeek-Harness-Konfiguration",
"configDescription": "Endpunkt und Schlüssel sind Umgebungsvariablen, die deepseek-acp beim Start liest. Modell und Denkstufe sind Auswahlfelder pro Sitzung — sie werden im Eingabefeld gewählt.",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Kiro-Konfiguration gespeichert",
"saveKiroFailed": "Kiro-Konfiguration konnte nicht gespeichert werden",
+ "traeSaved": "TRAE CLI-Konfiguration gespeichert",
+ "saveTraeFailed": "TRAE CLI-Konfiguration konnte nicht gespeichert werden",
+ "commandCodeSaved": "Command Code-Konfiguration gespeichert",
+ "saveCommandCodeFailed": "Command Code-Konfiguration konnte nicht gespeichert werden",
"systemAgentAlreadyLatest": "{name} ist bereits aktuell ({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "Einträge"
},
"noFolderTitle": "Kein Ordner geöffnet",
- "noFolderHint": "Öffnen Sie einen Ordner, um seinen Inhalt hier zu sehen"
+ "noFolderHint": "Öffnen Sie einen Ordner, um seinen Inhalt hier zu sehen",
+ "openFullPage": "Als ganze Seite öffnen",
+ "back": "Zurück",
+ "noAutomations": "Für dieses Projekt gibt es noch keine Automatisierungen"
},
"windowControls": {
"minimizeWindow": "Fenster minimieren",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "Fragen Sie alles...",
+ "promptSuggestion": "{suggestion} (Tab zum Übernehmen)",
"removeAttachmentAria": "{name} entfernen",
"attachFiles": "Dateien anhängen",
"addActions": "Hinzufügen",
@@ -3395,6 +3420,10 @@
"searchModelAria": "Modelle suchen",
"modelListLabel": "Modelle",
"recommendedBadge": "Empfohlen",
+ "recommendedValue": "Empfohlen: {value}",
+ "searchOptions": "Optionen suchen...",
+ "searchOptionsAria": "Optionen suchen",
+ "noOptions": "Keine Optionen gefunden",
"noModels": "Keine Modelle gefunden",
"cancel": "Abbrechen",
"send": "Senden",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "Nachrichtennavigation",
- "collapse": "Nachrichtennavigation ausblenden",
"loadingEarlier": "Frühere Nachrichten werden geladen…",
"loadEarlier": "Frühere Nachrichten laden",
- "collapsedSummary": "Nachrichten {count}",
"fileCount": "{count, plural, one {# Datei} other {# Dateien}}",
- "remove": "Entfernen",
- "noDiffDataAvailable": "Keine Diff-Daten verfügbar für {filePath}"
+ "subAgentCount": "{count, plural, one {# Subagent} other {# Subagenten}}",
+ "showDiff": "Änderungen an {filePath} anzeigen",
+ "hideDiff": "Änderungen an {filePath} ausblenden",
+ "openFile": "{filePath} öffnen",
+ "collapse": "Einklappen",
+ "currentMessage": "Aktuelle Nachricht",
+ "scrollToCurrent": "Zur aktuellen Nachricht (#{ordinal}) scrollen"
},
"replyArtifacts": {
"title": "Geänderte Dateien",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "Aufgabe {task} wird fortgesetzt",
"resumeDelegationNoId": "Delegierte Aufgabe wird fortgesetzt",
"promptLabel": "Anweisung",
+ "ackRecorded": "In der Arbeitsaufgabe erfasst",
+ "ackNotRecorded": "Nicht in der Arbeitsaufgabe erfasst",
+ "ackNotRecordedWithReason": "Nicht in der Arbeitsaufgabe erfasst: {reason}",
"verdict": {
"success": "erfolgreich",
"needs_review": "Prüfung nötig",
@@ -4188,6 +4223,18 @@
"stopDeclined": "Diese Aufgabe konnte nicht gestoppt werden – sie ist möglicherweise bereits beendet.",
"stopFailed": "Aufgabe konnte nicht gestoppt werden: {error}"
},
+ "remoteControl": {
+ "title": "Fernsteuerung aktiv",
+ "open": "Im Browser öffnen",
+ "copy": "Link kopieren",
+ "copied": "Kopiert",
+ "qr": "QR-Code",
+ "qrLabel": "QR-Code des Fernsteuerungs-Links dieser Sitzung",
+ "qrHint": "Mit dem Handy scannen, um diese Sitzung in der Claude-App oder auf claude.ai/code fortzusetzen.",
+ "noUrl": "Claude Code hat keinen Link für diese Sitzung zurückgegeben",
+ "turnOff": "Ausschalten",
+ "turnOffBusy": "Verfügbar, sobald Claude fertig ist"
+ },
"proposedPlan": {
"title": "Vorgeschlagener Plan",
"planning": "Wird geplant…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "Schwebekugel",
- "panelTitle": "Schnellaktionen",
- "settingsTitle": "Schwebekugel",
- "close": "Schließen",
- "resetPosition": "Position zurücksetzen",
- "cheatSheetTitle": "Gesten",
- "hint": "Ziehe die Kugel, um sie zu verschieben. Schnelles Wischen löst eine Geste aus, langes Drücken öffnet dieses Panel.",
"actions": {
"newConversation": "Neue Unterhaltung",
"toggleSidebar": "Seitenleiste umschalten",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ dann →",
"upRightThenLeft": "↗ dann ←"
},
- "favoriteAgentsEmpty": "Keine Agenten verfügbar",
"toasts": {
"renameNeedsSavedSession": "Umbenennen gilt nur für gespeicherte Sitzungen – senden Sie zuerst eine Nachricht.",
"sessionFolderNeedsWorkspace": "Öffnen Sie zuerst einen Arbeitsbereich-Ordner.",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "Dieser Agent stellt keine Modi bereit.",
"noSwitchTarget": "Kein Modus zum Wechseln gefunden (Plan- oder Vollzugriffsmodus fehlt)."
},
+ "label": "Schwebekugel",
+ "panelTitle": "Schnellaktionen",
+ "settingsTitle": "Schwebekugel",
+ "close": "Schließen",
+ "resetPosition": "Position zurücksetzen",
+ "cheatSheetTitle": "Gesten",
+ "hint": "Ziehe die Kugel, um sie zu verschieben. Schnelles Wischen löst eine Geste aus, langes Drücken öffnet dieses Panel.",
+ "favoriteAgentsEmpty": "Keine Agenten verfügbar",
"recentSessionDepth": "Umschalttiefe letzte Sitzungen",
"bindingCleared": "Nicht zugewiesen"
}
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index 5a5cf2ac7b..6d48274d81 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -181,13 +181,6 @@
"sectionDescription": "Entrance, expand/collapse, tool-call and working-status animations in the conversation area, plus smooth scrolling. Turn off for instant, motion-free updates. Spinners keep rotating.",
"enable": "Enable chat animations"
},
- "messageNav": {
- "sectionTitle": "Message navigator",
- "sectionDescription": "Where the per-conversation message navigator sits. Bottom-right keeps it as a compact one-row-per-turn card above the composer, out of the reading column.",
- "positionStart": "Top-left (default)",
- "positionBottomEnd": "Bottom-right (compact)",
- "hint": "Plan and sub-agent panels stay top-left either way."
- },
"chatWidth": {
"sectionTitle": "Chat width",
"sectionDescription": "Maximum width of the conversation column and the composer. You can also drag the edges of the chat column to adjust it.",
@@ -247,54 +240,6 @@
"credit": "Images from wallhaven.cc · SFW only"
}
},
- "floatingBall": {
- "sectionTitle": "Floating Ball",
- "sectionDescription": "A draggable ball over the workspace that turns swipes into shortcuts — built for the phone, where there is no keyboard.",
- "enable": "Show floating ball",
- "hint": "Drag to move; swipe quickly for a gesture; long press for the panel and cheat sheet.",
- "resetPosition": "Reset position",
- "ballSize": "Ball size",
- "sizeSmall": "Small",
- "sizeMedium": "Medium",
- "sizeLarge": "Large",
- "gestureBindings": "Gesture bindings",
- "bindingCleared": "Unbound",
- "favoriteAgents": "Favorite agents",
- "favoriteAgentsHint": "Pick 2-3 agents to cycle through with the favorite-agents gesture.",
- "favoriteAgentsEmpty": "No available agents",
- "panelTitle": "Quick actions"
- },
- "gestures": {
- "tap": "Tap",
- "doubleTap": "Double tap",
- "longPress": "Long press",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ then ←",
- "upThenRight": "↑ then →",
- "upDown": "↑ then ↓",
- "leftThenRight": "← then →",
- "rightThenLeft": "→ then ←",
- "upLeftThenDown": "↖ then ↓",
- "upRightThenDown": "↗ then ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ then ↑",
- "upThenDownRight": "↑ then ↘",
- "downThenUpRight": "↓ then ↗",
- "rightThenUp": "→ then ↑",
- "rightThenDown": "→ then ↓",
- "downThenRight": "↓ then →",
- "downThenLeft": "↓ then ←",
- "downRightThenUp": "↘ then ↑",
- "downLeftThenUp": "↙ then ↑",
- "upLeftThenRight": "↖ then →",
- "upRightThenLeft": "↗ then ←"
- },
"actions": {
"newConversation": "New conversation",
"toggleSidebar": "Toggle sidebar",
@@ -328,6 +273,54 @@
"focusModeSelector": "Mode selector",
"togglePlanFullAccess": "Plan / full access",
"openCollaboration": "Collaboration"
+ },
+ "gestures": {
+ "tap": "Tap",
+ "doubleTap": "Double tap",
+ "longPress": "Long press",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ then ←",
+ "upThenRight": "↑ then →",
+ "upDown": "↑ then ↓",
+ "leftThenRight": "← then →",
+ "rightThenLeft": "→ then ←",
+ "upLeftThenDown": "↖ then ↓",
+ "upRightThenDown": "↗ then ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ then ↑",
+ "upThenDownRight": "↑ then ↘",
+ "downThenUpRight": "↓ then ↗",
+ "rightThenUp": "→ then ↑",
+ "rightThenDown": "→ then ↓",
+ "downThenRight": "↓ then →",
+ "downThenLeft": "↓ then ←",
+ "downRightThenUp": "↘ then ↑",
+ "downLeftThenUp": "↙ then ↑",
+ "upLeftThenRight": "↖ then →",
+ "upRightThenLeft": "↗ then ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "Floating Ball",
+ "sectionDescription": "A draggable ball over the workspace that turns swipes into shortcuts — built for the phone, where there is no keyboard.",
+ "enable": "Show floating ball",
+ "hint": "Drag to move; swipe quickly for a gesture; long press for the panel and cheat sheet.",
+ "resetPosition": "Reset position",
+ "ballSize": "Ball size",
+ "sizeSmall": "Small",
+ "sizeMedium": "Medium",
+ "sizeLarge": "Large",
+ "gestureBindings": "Gesture bindings",
+ "bindingCleared": "Unbound",
+ "favoriteAgents": "Favorite agents",
+ "favoriteAgentsHint": "Pick 2-3 agents to cycle through with the favorite-agents gesture.",
+ "favoriteAgentsEmpty": "No available agents",
+ "panelTitle": "Quick actions"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "Passed to the CLI as KIRO_API_KEY. Leave empty to use the account you signed in with via kiro-cli login; an API key is only needed where no browser sign-in is possible (servers, Docker).",
"saveConfig": "Save Kiro Config"
},
+ "trae": {
+ "configManagement": "Configuration",
+ "configDescription": "TRAE CLI 2.0 is available to customers on the flagship TRAE Enterprise plan. Codeg runs the traecli you installed, which keeps its sign-in, skills and MCP servers in ~/.trae. Model, mode and reasoning effort are not here: TRAE CLI reports them over ACP, so the composer's own selectors own them per session.",
+ "signInTitle": "Sign in",
+ "signInHint": "Run this once in a terminal to sign in with your enterprise SSO. Sessions in Codeg reuse that login.",
+ "copyCommand": "Copy command",
+ "commandCopied": "Command copied",
+ "patLabel": "Personal access token (optional)",
+ "patHint": "For a machine where browser sign-in is not possible, such as a server or Docker install. Codeg passes it to TRAE CLI as TRAECLI_PERSONAL_ACCESS_TOKEN and signs in with it whenever a session starts. Leave empty to use the login from traecli login.",
+ "hostLabel": "Enterprise API URL (optional)",
+ "hostHint": "Only if your organization runs TRAE on its own domain. Passed as TRAECLI_HOST; leave empty for TRAE's own service.",
+ "saveConfig": "Save TRAE CLI Config"
+ },
+ "commandCode": {
+ "configManagement": "Configuration",
+ "configDescription": "Codeg runs the Command Code CLI from the command-code npm package, which keeps its sign-in, skills and MCP servers in ~/.commandcode. Model, mode and reasoning effort are not here: Command Code reports them over ACP, so the composer's own selectors own them per session.",
+ "signInTitle": "Sign in",
+ "signInHint": "Run this once in a terminal to sign in with your Command Code account. Sessions in Codeg reuse that login.",
+ "copyCommand": "Copy command",
+ "commandCopied": "Command copied",
+ "apiKeyLabel": "API key (optional)",
+ "apiKeyHint": "For a machine where browser sign-in is not possible, such as a server or Docker install. Passed to Command Code as COMMAND_CODE_API_KEY, which takes precedence over the login from command-code login. Leave empty to use that login.",
+ "saveConfig": "Save Command Code Config"
+ },
"deepseek": {
"configManagement": "DeepSeek Harness Configuration",
"configDescription": "The endpoint and key are environment variables deepseek-acp reads at launch. Model and reasoning effort are per-session selectors — pick them in the composer.",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Kiro config saved",
"saveKiroFailed": "Failed to save Kiro config",
+ "traeSaved": "TRAE CLI config saved",
+ "saveTraeFailed": "Failed to save TRAE CLI config",
+ "commandCodeSaved": "Command Code config saved",
+ "saveCommandCodeFailed": "Failed to save Command Code config",
"systemAgentAlreadyLatest": "{name} is already up to date ({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "Commits"
},
"noFolderTitle": "No folder open",
- "noFolderHint": "Open a folder to see its contents here"
+ "noFolderHint": "Open a folder to see its contents here",
+ "openFullPage": "Open full page",
+ "back": "Back",
+ "noAutomations": "No automations for this project yet"
},
"windowControls": {
"minimizeWindow": "Minimize window",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "Ask anything...",
+ "promptSuggestion": "{suggestion} (Tab to use)",
"removeAttachmentAria": "Remove {name}",
"attachFiles": "Attach files",
"attachLocalUpload": "Upload local file",
@@ -3397,6 +3422,10 @@
"searchModelAria": "Search models",
"modelListLabel": "Models",
"recommendedBadge": "Recommended",
+ "recommendedValue": "Recommended: {value}",
+ "searchOptions": "Search options...",
+ "searchOptionsAria": "Search options",
+ "noOptions": "No options found",
"noModels": "No models found",
"cancel": "Cancel",
"send": "Send",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "Message navigation",
- "collapse": "Collapse message navigation",
"loadingEarlier": "Loading earlier messages…",
"loadEarlier": "Load earlier messages",
- "collapsedSummary": "Messages {count}",
"fileCount": "{count, plural, one {# file} other {# files}}",
- "remove": "Remove",
- "noDiffDataAvailable": "No diff data available for {filePath}"
+ "subAgentCount": "{count, plural, one {# sub-agent} other {# sub-agents}}",
+ "showDiff": "Show the changes to {filePath}",
+ "hideDiff": "Hide the changes to {filePath}",
+ "openFile": "Open {filePath}",
+ "collapse": "Collapse",
+ "currentMessage": "Current message",
+ "scrollToCurrent": "Scroll to the current message (#{ordinal})"
},
"replyArtifacts": {
"title": "Files changed",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "Resuming task {task}",
"resumeDelegationNoId": "Resuming a delegated task",
"promptLabel": "Prompt",
+ "ackRecorded": "Recorded on the work task",
+ "ackNotRecorded": "Not recorded on the work task",
+ "ackNotRecordedWithReason": "Not recorded on the work task: {reason}",
"verdict": {
"success": "success",
"needs_review": "needs review",
@@ -4188,6 +4223,18 @@
"stopDeclined": "That task could not be stopped — it may have already finished.",
"stopFailed": "Failed to stop the task: {error}"
},
+ "remoteControl": {
+ "title": "Remote Control is on",
+ "open": "Open in browser",
+ "copy": "Copy link",
+ "copied": "Copied",
+ "qr": "QR code",
+ "qrLabel": "QR code for this session's Remote Control link",
+ "qrHint": "Scan with your phone to continue this session in the Claude app or on claude.ai/code.",
+ "noUrl": "Claude Code returned no link for this session",
+ "turnOff": "Turn off",
+ "turnOffBusy": "Available once Claude has finished"
+ },
"proposedPlan": {
"title": "Proposed plan",
"planning": "Planning…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "Floating ball",
- "panelTitle": "Quick actions",
- "settingsTitle": "Floating ball",
- "close": "Close",
- "resetPosition": "Reset position",
- "cheatSheetTitle": "Gestures",
- "hint": "Drag the ball to move it. Swipe quickly for a gesture; press and hold to open this panel.",
"actions": {
"newConversation": "New conversation",
"toggleSidebar": "Toggle sidebar",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ then →",
"upRightThenLeft": "↗ then ←"
},
- "favoriteAgentsEmpty": "No available agents",
"toasts": {
"renameNeedsSavedSession": "Rename works on a saved session — send a message first.",
"sessionFolderNeedsWorkspace": "Open a workspace folder first.",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "This agent does not expose any modes.",
"noSwitchTarget": "No mode to switch to (Plan or full-access mode not found)."
},
+ "label": "Floating ball",
+ "panelTitle": "Quick actions",
+ "settingsTitle": "Floating ball",
+ "close": "Close",
+ "resetPosition": "Reset position",
+ "cheatSheetTitle": "Gestures",
+ "hint": "Drag the ball to move it. Swipe quickly for a gesture; press and hold to open this panel.",
+ "favoriteAgentsEmpty": "No available agents",
"recentSessionDepth": "Recent-session switch depth",
"bindingCleared": "Unbound"
}
diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json
index fa70d2dc1b..e0e81639c7 100644
--- a/src/i18n/messages/es.json
+++ b/src/i18n/messages/es.json
@@ -181,13 +181,6 @@
"sectionDescription": "Animaciones de plegado/desplegado, llamadas a herramientas y estado de trabajo en el área de conversación, además del desplazamiento suave. Desactívalas para actualizaciones inmediatas. Los indicadores de carga siguen girando.",
"enable": "Activar las animaciones del chat"
},
- "messageNav": {
- "sectionTitle": "Navegador de mensajes",
- "sectionDescription": "Posición del navegador de mensajes. Abajo a la derecha se convierte en una tarjeta compacta con una fila por mensaje del usuario, sobre el cuadro de entrada.",
- "positionStart": "Arriba a la izquierda (predeterminado)",
- "positionBottomEnd": "Abajo a la derecha (compacto)",
- "hint": "Los paneles de plan y de subagentes siguen arriba a la izquierda."
- },
"chatWidth": {
"sectionTitle": "Ancho del chat",
"sectionDescription": "Ancho máximo de la columna de conversación y del cuadro de entrada. También puedes arrastrar los bordes del chat para ajustarlo.",
@@ -247,54 +240,6 @@
"credit": "Imágenes de wallhaven.cc · solo SFW"
}
},
- "floatingBall": {
- "sectionTitle": "Bola flotante",
- "sectionDescription": "Una bola arrastrable sobre el espacio de trabajo que convierte los deslizamientos en atajos, pensada para el teléfono, donde no hay teclado.",
- "enable": "Mostrar bola flotante",
- "hint": "Arrastra para mover, desliza rápido para un gesto, mantén pulsado para el panel y la lista de gestos.",
- "resetPosition": "Restablecer posición",
- "ballSize": "Tamaño de la bola",
- "sizeSmall": "Pequeño",
- "sizeMedium": "Mediano",
- "sizeLarge": "Grande",
- "gestureBindings": "Asignación de gestos",
- "bindingCleared": "Sin asignar",
- "favoriteAgents": "Agentes favoritos",
- "favoriteAgentsHint": "Elige 2-3 agentes para alternar con el gesto de favoritos.",
- "favoriteAgentsEmpty": "No hay agentes disponibles",
- "panelTitle": "Acciones rápidas"
- },
- "gestures": {
- "tap": "Toque",
- "doubleTap": "Doble toque",
- "longPress": "Mantener pulsado",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ luego ←",
- "upThenRight": "↑ luego →",
- "upDown": "↑ luego ↓",
- "leftThenRight": "← luego →",
- "rightThenLeft": "→ luego ←",
- "upLeftThenDown": "↖ luego ↓",
- "upRightThenDown": "↗ luego ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ luego ↑",
- "upThenDownRight": "↑ luego ↘",
- "downThenUpRight": "↓ luego ↗",
- "rightThenUp": "→ luego ↑",
- "rightThenDown": "→ luego ↓",
- "downThenRight": "↓ luego →",
- "downThenLeft": "↓ luego ←",
- "downRightThenUp": "↘ luego ↑",
- "downLeftThenUp": "↙ luego ↑",
- "upLeftThenRight": "↖ luego →",
- "upRightThenLeft": "↗ luego ←"
- },
"actions": {
"newConversation": "Nueva conversación",
"toggleSidebar": "Mostrar u ocultar la barra lateral",
@@ -328,6 +273,54 @@
"focusModeSelector": "Selector de modo",
"togglePlanFullAccess": "Plan / acceso total",
"openCollaboration": "Colaboración"
+ },
+ "gestures": {
+ "tap": "Toque",
+ "doubleTap": "Doble toque",
+ "longPress": "Mantener pulsado",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ luego ←",
+ "upThenRight": "↑ luego →",
+ "upDown": "↑ luego ↓",
+ "leftThenRight": "← luego →",
+ "rightThenLeft": "→ luego ←",
+ "upLeftThenDown": "↖ luego ↓",
+ "upRightThenDown": "↗ luego ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ luego ↑",
+ "upThenDownRight": "↑ luego ↘",
+ "downThenUpRight": "↓ luego ↗",
+ "rightThenUp": "→ luego ↑",
+ "rightThenDown": "→ luego ↓",
+ "downThenRight": "↓ luego →",
+ "downThenLeft": "↓ luego ←",
+ "downRightThenUp": "↘ luego ↑",
+ "downLeftThenUp": "↙ luego ↑",
+ "upLeftThenRight": "↖ luego →",
+ "upRightThenLeft": "↗ luego ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "Bola flotante",
+ "sectionDescription": "Una bola arrastrable sobre el espacio de trabajo que convierte los deslizamientos en atajos, pensada para el teléfono, donde no hay teclado.",
+ "enable": "Mostrar bola flotante",
+ "hint": "Arrastra para mover, desliza rápido para un gesto, mantén pulsado para el panel y la lista de gestos.",
+ "resetPosition": "Restablecer posición",
+ "ballSize": "Tamaño de la bola",
+ "sizeSmall": "Pequeño",
+ "sizeMedium": "Mediano",
+ "sizeLarge": "Grande",
+ "gestureBindings": "Asignación de gestos",
+ "bindingCleared": "Sin asignar",
+ "favoriteAgents": "Agentes favoritos",
+ "favoriteAgentsHint": "Elige 2-3 agentes para alternar con el gesto de favoritos.",
+ "favoriteAgentsEmpty": "No hay agentes disponibles",
+ "panelTitle": "Acciones rápidas"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "Se pasa a la CLI como KIRO_API_KEY. Déjala vacía para usar la cuenta con la que iniciaste sesión mediante kiro-cli login; solo hace falta donde no se puede iniciar sesión con el navegador (servidores, Docker).",
"saveConfig": "Guardar configuración de Kiro"
},
+ "trae": {
+ "configManagement": "Configuración",
+ "configDescription": "TRAE CLI 2.0 solo está disponible para clientes del plan insignia de TRAE Enterprise. Codeg ejecuta el traecli que instalaste, que guarda su inicio de sesión, sus habilidades y sus servidores MCP en ~/.trae. El modelo, el modo y el esfuerzo de razonamiento no están aquí: TRAE CLI los informa por ACP, así que los selectores del compositor los gestionan en cada sesión.",
+ "signInTitle": "Iniciar sesión",
+ "signInHint": "Ejecuta esto una vez en una terminal para iniciar sesión con el SSO de tu empresa. Las sesiones de Codeg reutilizan ese inicio de sesión.",
+ "copyCommand": "Copiar comando",
+ "commandCopied": "Comando copiado",
+ "patLabel": "Token de acceso personal (opcional)",
+ "patHint": "Para una máquina donde no se puede iniciar sesión con el navegador, como un servidor o una instalación de Docker. Codeg lo pasa a TRAE CLI como TRAECLI_PERSONAL_ACCESS_TOKEN e inicia sesión con él cada vez que empieza una sesión. Déjalo vacío para usar el inicio de sesión de traecli login.",
+ "hostLabel": "URL de la API empresarial (opcional)",
+ "hostHint": "Solo si tu organización ejecuta TRAE en su propio dominio. Se pasa como TRAECLI_HOST; déjala vacía para usar el servicio de TRAE.",
+ "saveConfig": "Guardar configuración de TRAE CLI"
+ },
+ "commandCode": {
+ "configManagement": "Configuración",
+ "configDescription": "Codeg ejecuta la CLI de Command Code del paquete npm command-code, que guarda su inicio de sesión, sus habilidades y sus servidores MCP en ~/.commandcode. El modelo, el modo y el esfuerzo de razonamiento no están aquí: Command Code los informa por ACP, así que los selectores del compositor los gestionan en cada sesión.",
+ "signInTitle": "Iniciar sesión",
+ "signInHint": "Ejecuta esto una vez en una terminal para iniciar sesión con tu cuenta de Command Code. Las sesiones de Codeg reutilizan ese inicio de sesión.",
+ "copyCommand": "Copiar comando",
+ "commandCopied": "Comando copiado",
+ "apiKeyLabel": "Clave de API (opcional)",
+ "apiKeyHint": "Para una máquina donde no se puede iniciar sesión con el navegador, como un servidor o una instalación de Docker. Se pasa a Command Code como COMMAND_CODE_API_KEY, que tiene prioridad sobre el inicio de sesión de command-code login. Déjala vacía para usar ese inicio de sesión.",
+ "saveConfig": "Guardar configuración de Command Code"
+ },
"deepseek": {
"configManagement": "Configuración de DeepSeek Harness",
"configDescription": "El endpoint y la clave son variables de entorno que deepseek-acp lee al arrancar. El modelo y el esfuerzo de razonamiento son selectores por sesión: se eligen en el campo de mensaje.",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Configuración de Kiro guardada",
"saveKiroFailed": "No se pudo guardar la configuración de Kiro",
+ "traeSaved": "Configuración de TRAE CLI guardada",
+ "saveTraeFailed": "No se pudo guardar la configuración de TRAE CLI",
+ "commandCodeSaved": "Configuración de Command Code guardada",
+ "saveCommandCodeFailed": "No se pudo guardar la configuración de Command Code",
"systemAgentAlreadyLatest": "{name} ya está al día ({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "Confirmaciones"
},
"noFolderTitle": "No hay carpeta abierta",
- "noFolderHint": "Abre una carpeta para ver su contenido aquí"
+ "noFolderHint": "Abre una carpeta para ver su contenido aquí",
+ "openFullPage": "Abrir en página completa",
+ "back": "Atrás",
+ "noAutomations": "Este proyecto aún no tiene automatizaciones"
},
"windowControls": {
"minimizeWindow": "Minimizar ventana",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "Pregunta lo que sea...",
+ "promptSuggestion": "{suggestion} (Tab para usarla)",
"removeAttachmentAria": "Quitar {name}",
"attachFiles": "Adjuntar archivos",
"addActions": "Añadir",
@@ -3395,6 +3420,10 @@
"searchModelAria": "Buscar modelos",
"modelListLabel": "Modelos",
"recommendedBadge": "Recomendado",
+ "recommendedValue": "Recomendado: {value}",
+ "searchOptions": "Buscar opciones...",
+ "searchOptionsAria": "Buscar opciones",
+ "noOptions": "No se encontraron opciones",
"noModels": "No se encontraron modelos",
"cancel": "Cancelar",
"send": "Enviar",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "Navegación de mensajes",
- "collapse": "Contraer navegación de mensajes",
"loadingEarlier": "Cargando mensajes anteriores…",
"loadEarlier": "Cargar mensajes anteriores",
- "collapsedSummary": "Mensajes {count}",
"fileCount": "{count, plural, one {# archivo} other {# archivos}}",
- "remove": "Quitar",
- "noDiffDataAvailable": "No hay datos de diff disponibles para {filePath}"
+ "subAgentCount": "{count, plural, one {# subagente} other {# subagentes}}",
+ "showDiff": "Mostrar los cambios de {filePath}",
+ "hideDiff": "Ocultar los cambios de {filePath}",
+ "openFile": "Abrir {filePath}",
+ "collapse": "Contraer",
+ "currentMessage": "Mensaje actual",
+ "scrollToCurrent": "Desplazarse al mensaje actual (#{ordinal})"
},
"replyArtifacts": {
"title": "Archivos modificados",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "Reanudando la tarea {task}",
"resumeDelegationNoId": "Reanudando una tarea delegada",
"promptLabel": "Instrucción",
+ "ackRecorded": "Registrado en la tarea de trabajo",
+ "ackNotRecorded": "No registrado en la tarea de trabajo",
+ "ackNotRecordedWithReason": "No registrado en la tarea de trabajo: {reason}",
"verdict": {
"success": "correcta",
"needs_review": "requiere revisión",
@@ -4188,6 +4223,18 @@
"stopDeclined": "No se pudo detener esa tarea; puede que ya haya terminado.",
"stopFailed": "No se pudo detener la tarea: {error}"
},
+ "remoteControl": {
+ "title": "Control remoto activado",
+ "open": "Abrir en el navegador",
+ "copy": "Copiar enlace",
+ "copied": "Copiado",
+ "qr": "Código QR",
+ "qrLabel": "Código QR del enlace de control remoto de esta sesión",
+ "qrHint": "Escanéalo con el teléfono para continuar esta sesión en la app de Claude o en claude.ai/code.",
+ "noUrl": "Claude Code no devolvió ningún enlace para esta sesión",
+ "turnOff": "Desactivar",
+ "turnOffBusy": "Disponible cuando Claude termine"
+ },
"proposedPlan": {
"title": "Plan propuesto",
"planning": "Planificando…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "Bola flotante",
- "panelTitle": "Acciones rápidas",
- "settingsTitle": "Bola flotante",
- "close": "Cerrar",
- "resetPosition": "Restablecer posición",
- "cheatSheetTitle": "Gestos",
- "hint": "Arrastra la bola para moverla. Un deslizamiento rápido activa un gesto; una pulsación larga abre este panel.",
"actions": {
"newConversation": "Nueva conversación",
"toggleSidebar": "Mostrar u ocultar la barra lateral",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ luego →",
"upRightThenLeft": "↗ luego ←"
},
- "favoriteAgentsEmpty": "No hay agentes disponibles",
"toasts": {
"renameNeedsSavedSession": "Renombrar solo funciona en sesiones guardadas: envía un mensaje primero.",
"sessionFolderNeedsWorkspace": "Abre antes una carpeta de espacio de trabajo.",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "Este agente no expone ningún modo.",
"noSwitchTarget": "No hay modo al que cambiar (no se encontró modo Plan ni de acceso completo)."
},
+ "label": "Bola flotante",
+ "panelTitle": "Acciones rápidas",
+ "settingsTitle": "Bola flotante",
+ "close": "Cerrar",
+ "resetPosition": "Restablecer posición",
+ "cheatSheetTitle": "Gestos",
+ "hint": "Arrastra la bola para moverla. Un deslizamiento rápido activa un gesto; una pulsación larga abre este panel.",
+ "favoriteAgentsEmpty": "No hay agentes disponibles",
"recentSessionDepth": "Profundidad de sesiones recientes",
"bindingCleared": "Sin asignar"
}
diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json
index 7a4b3a2930..9aa339486c 100644
--- a/src/i18n/messages/fr.json
+++ b/src/i18n/messages/fr.json
@@ -181,13 +181,6 @@
"sectionDescription": "Animations de pliage/dépliage, d'appels d'outils et d'état de travail dans la zone de conversation, ainsi que le défilement fluide. Désactivez-les pour des mises à jour instantanées. Les indicateurs de chargement continuent de tourner.",
"enable": "Activer les animations du chat"
},
- "messageNav": {
- "sectionTitle": "Navigateur de messages",
- "sectionDescription": "Position du navigateur de messages. En bas à droite, il devient une carte compacte avec une ligne par message utilisateur, au-dessus de la zone de saisie.",
- "positionStart": "En haut à gauche (par défaut)",
- "positionBottomEnd": "En bas à droite (compact)",
- "hint": "Les panneaux de plan et de sous-agents restent en haut à gauche."
- },
"chatWidth": {
"sectionTitle": "Largeur du chat",
"sectionDescription": "Largeur maximale de la colonne de conversation et de la zone de saisie. Vous pouvez aussi faire glisser les bords du chat pour l'ajuster.",
@@ -247,54 +240,6 @@
"credit": "Images de wallhaven.cc · SFW uniquement"
}
},
- "floatingBall": {
- "sectionTitle": "Boule flottante",
- "sectionDescription": "Une boule déplaçable au-dessus de l’espace de travail qui transforme les balayages en raccourcis — pensée pour le téléphone, où il n’y a pas de clavier.",
- "enable": "Afficher la boule flottante",
- "hint": "Faites glisser pour déplacer, balayez rapidement pour un geste, appuyez longuement pour le panneau et la liste des gestes.",
- "resetPosition": "Réinitialiser la position",
- "ballSize": "Taille de la bille",
- "sizeSmall": "Petite",
- "sizeMedium": "Moyenne",
- "sizeLarge": "Grande",
- "gestureBindings": "Affectation des gestes",
- "bindingCleared": "Non attribué",
- "favoriteAgents": "Agents favoris",
- "favoriteAgentsHint": "Choisissez 2-3 agents à parcourir avec le geste des favoris.",
- "favoriteAgentsEmpty": "Aucun agent disponible",
- "panelTitle": "Actions rapides"
- },
- "gestures": {
- "tap": "Touche",
- "doubleTap": "Double touche",
- "longPress": "Appui long",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ puis ←",
- "upThenRight": "↑ puis →",
- "upDown": "↑ puis ↓",
- "leftThenRight": "← puis →",
- "rightThenLeft": "→ puis ←",
- "upLeftThenDown": "↖ puis ↓",
- "upRightThenDown": "↗ puis ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ puis ↑",
- "upThenDownRight": "↑ puis ↘",
- "downThenUpRight": "↓ puis ↗",
- "rightThenUp": "→ puis ↑",
- "rightThenDown": "→ puis ↓",
- "downThenRight": "↓ puis →",
- "downThenLeft": "↓ puis ←",
- "downRightThenUp": "↘ puis ↑",
- "downLeftThenUp": "↙ puis ↑",
- "upLeftThenRight": "↖ puis →",
- "upRightThenLeft": "↗ puis ←"
- },
"actions": {
"newConversation": "Nouvelle conversation",
"toggleSidebar": "Afficher ou masquer la barre latérale",
@@ -328,6 +273,54 @@
"focusModeSelector": "Sélecteur de mode",
"togglePlanFullAccess": "Plan / accès complet",
"openCollaboration": "Collaboration"
+ },
+ "gestures": {
+ "tap": "Touche",
+ "doubleTap": "Double touche",
+ "longPress": "Appui long",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ puis ←",
+ "upThenRight": "↑ puis →",
+ "upDown": "↑ puis ↓",
+ "leftThenRight": "← puis →",
+ "rightThenLeft": "→ puis ←",
+ "upLeftThenDown": "↖ puis ↓",
+ "upRightThenDown": "↗ puis ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ puis ↑",
+ "upThenDownRight": "↑ puis ↘",
+ "downThenUpRight": "↓ puis ↗",
+ "rightThenUp": "→ puis ↑",
+ "rightThenDown": "→ puis ↓",
+ "downThenRight": "↓ puis →",
+ "downThenLeft": "↓ puis ←",
+ "downRightThenUp": "↘ puis ↑",
+ "downLeftThenUp": "↙ puis ↑",
+ "upLeftThenRight": "↖ puis →",
+ "upRightThenLeft": "↗ puis ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "Boule flottante",
+ "sectionDescription": "Une boule déplaçable au-dessus de l’espace de travail qui transforme les balayages en raccourcis — pensée pour le téléphone, où il n’y a pas de clavier.",
+ "enable": "Afficher la boule flottante",
+ "hint": "Faites glisser pour déplacer, balayez rapidement pour un geste, appuyez longuement pour le panneau et la liste des gestes.",
+ "resetPosition": "Réinitialiser la position",
+ "ballSize": "Taille de la bille",
+ "sizeSmall": "Petite",
+ "sizeMedium": "Moyenne",
+ "sizeLarge": "Grande",
+ "gestureBindings": "Affectation des gestes",
+ "bindingCleared": "Non attribué",
+ "favoriteAgents": "Agents favoris",
+ "favoriteAgentsHint": "Choisissez 2-3 agents à parcourir avec le geste des favoris.",
+ "favoriteAgentsEmpty": "Aucun agent disponible",
+ "panelTitle": "Actions rapides"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "Transmise à la CLI en tant que KIRO_API_KEY. Laissez vide pour utiliser le compte connecté via kiro-cli login ; nécessaire seulement là où la connexion par navigateur est impossible (serveurs, Docker).",
"saveConfig": "Enregistrer la configuration Kiro"
},
+ "trae": {
+ "configManagement": "Configuration",
+ "configDescription": "TRAE CLI 2.0 est réservé aux clients de l'offre phare de TRAE Enterprise. Codeg lance le traecli que vous avez installé, qui conserve sa connexion, ses compétences et ses serveurs MCP dans ~/.trae. Le modèle, le mode et l'effort de raisonnement ne sont pas ici : TRAE CLI les communique via ACP, donc les sélecteurs du compositeur les gèrent pour chaque session.",
+ "signInTitle": "Connexion",
+ "signInHint": "Exécutez cette commande une fois dans un terminal pour vous connecter avec le SSO de votre entreprise. Les sessions de Codeg réutilisent cette connexion.",
+ "copyCommand": "Copier la commande",
+ "commandCopied": "Commande copiée",
+ "patLabel": "Jeton d'accès personnel (facultatif)",
+ "patHint": "Pour une machine où la connexion par navigateur est impossible, comme un serveur ou une installation Docker. Codeg le transmet à TRAE CLI en tant que TRAECLI_PERSONAL_ACCESS_TOKEN et se connecte avec lui au démarrage de chaque session. Laissez vide pour utiliser la connexion de traecli login.",
+ "hostLabel": "URL de l'API d'entreprise (facultative)",
+ "hostHint": "Uniquement si votre organisation exploite TRAE sur son propre domaine. Transmise en tant que TRAECLI_HOST ; laissez vide pour le service de TRAE.",
+ "saveConfig": "Enregistrer la configuration TRAE CLI"
+ },
+ "commandCode": {
+ "configManagement": "Configuration",
+ "configDescription": "Codeg lance la CLI Command Code du paquet npm command-code, qui conserve sa connexion, ses compétences et ses serveurs MCP dans ~/.commandcode. Le modèle, le mode et l'effort de raisonnement ne sont pas ici : Command Code les communique via ACP, donc les sélecteurs du compositeur les gèrent pour chaque session.",
+ "signInTitle": "Connexion",
+ "signInHint": "Exécutez cette commande une fois dans un terminal pour vous connecter avec votre compte Command Code. Les sessions de Codeg réutilisent cette connexion.",
+ "copyCommand": "Copier la commande",
+ "commandCopied": "Commande copiée",
+ "apiKeyLabel": "Clé d'API (facultative)",
+ "apiKeyHint": "Pour une machine où la connexion par navigateur est impossible, comme un serveur ou une installation Docker. Transmise à Command Code en tant que COMMAND_CODE_API_KEY, prioritaire sur la connexion de command-code login. Laissez vide pour utiliser cette connexion.",
+ "saveConfig": "Enregistrer la configuration Command Code"
+ },
"deepseek": {
"configManagement": "Configuration de DeepSeek Harness",
"configDescription": "Le point de terminaison et la clé sont des variables d'environnement que deepseek-acp lit au démarrage. Le modèle et le niveau de raisonnement sont des sélecteurs par session : ils se choisissent dans le champ de saisie.",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Configuration Kiro enregistrée",
"saveKiroFailed": "Impossible d'enregistrer la configuration Kiro",
+ "traeSaved": "Configuration TRAE CLI enregistrée",
+ "saveTraeFailed": "Impossible d'enregistrer la configuration TRAE CLI",
+ "commandCodeSaved": "Configuration Command Code enregistrée",
+ "saveCommandCodeFailed": "Impossible d'enregistrer la configuration Command Code",
"systemAgentAlreadyLatest": "{name} est déjà à jour ({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "Validations"
},
"noFolderTitle": "Aucun dossier ouvert",
- "noFolderHint": "Ouvrez un dossier pour voir son contenu ici"
+ "noFolderHint": "Ouvrez un dossier pour voir son contenu ici",
+ "openFullPage": "Ouvrir en pleine page",
+ "back": "Retour",
+ "noAutomations": "Aucune automatisation pour ce projet pour l’instant"
},
"windowControls": {
"minimizeWindow": "Minimiser la fenêtre",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "Posez n'importe quelle question...",
+ "promptSuggestion": "{suggestion} (Tab pour l’utiliser)",
"removeAttachmentAria": "Retirer {name}",
"attachFiles": "Joindre des fichiers",
"addActions": "Ajouter",
@@ -3395,6 +3420,10 @@
"searchModelAria": "Rechercher des modèles",
"modelListLabel": "Modèles",
"recommendedBadge": "Recommandé",
+ "recommendedValue": "Recommandé : {value}",
+ "searchOptions": "Rechercher des options...",
+ "searchOptionsAria": "Rechercher des options",
+ "noOptions": "Aucune option trouvée",
"noModels": "Aucun modèle trouvé",
"cancel": "Annuler",
"send": "Envoyer",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "Navigation des messages",
- "collapse": "Réduire la navigation des messages",
"loadingEarlier": "Chargement des messages précédents…",
"loadEarlier": "Charger les messages précédents",
- "collapsedSummary": "Messages {count}",
"fileCount": "{count, plural, one {# fichier} other {# fichiers}}",
- "remove": "Retirer",
- "noDiffDataAvailable": "Aucune donnée de diff disponible pour {filePath}"
+ "subAgentCount": "{count, plural, one {# sous-agent} other {# sous-agents}}",
+ "showDiff": "Afficher les modifications de {filePath}",
+ "hideDiff": "Masquer les modifications de {filePath}",
+ "openFile": "Ouvrir {filePath}",
+ "collapse": "Réduire",
+ "currentMessage": "Message actuel",
+ "scrollToCurrent": "Faire défiler jusqu’au message actuel (#{ordinal})"
},
"replyArtifacts": {
"title": "Fichiers modifiés",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "Reprise de la tâche {task}",
"resumeDelegationNoId": "Reprise d'une tâche déléguée",
"promptLabel": "Instruction",
+ "ackRecorded": "Enregistré dans la tâche",
+ "ackNotRecorded": "Non enregistré dans la tâche",
+ "ackNotRecordedWithReason": "Non enregistré dans la tâche : {reason}",
"verdict": {
"success": "réussie",
"needs_review": "à relire",
@@ -4188,6 +4223,18 @@
"stopDeclined": "Impossible d'arrêter cette tâche : elle est peut-être déjà terminée.",
"stopFailed": "Échec de l'arrêt de la tâche : {error}"
},
+ "remoteControl": {
+ "title": "Contrôle à distance activé",
+ "open": "Ouvrir dans le navigateur",
+ "copy": "Copier le lien",
+ "copied": "Copié",
+ "qr": "Code QR",
+ "qrLabel": "Code QR du lien de contrôle à distance de cette session",
+ "qrHint": "Scannez-le avec votre téléphone pour poursuivre cette session dans l'app Claude ou sur claude.ai/code.",
+ "noUrl": "Claude Code n'a renvoyé aucun lien pour cette session",
+ "turnOff": "Désactiver",
+ "turnOffBusy": "Disponible une fois que Claude a terminé"
+ },
"proposedPlan": {
"title": "Plan proposé",
"planning": "Planification…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "Boule flottante",
- "panelTitle": "Actions rapides",
- "settingsTitle": "Boule flottante",
- "close": "Fermer",
- "resetPosition": "Réinitialiser la position",
- "cheatSheetTitle": "Gestes",
- "hint": "Faites glisser la boule pour la déplacer. Un balayage rapide déclenche un geste, un appui long ouvre ce panneau.",
"actions": {
"newConversation": "Nouvelle conversation",
"toggleSidebar": "Afficher ou masquer la barre latérale",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ puis →",
"upRightThenLeft": "↗ puis ←"
},
- "favoriteAgentsEmpty": "Aucun agent disponible",
"toasts": {
"renameNeedsSavedSession": "Renommer ne s'applique qu'aux sessions enregistrées — envoyez d'abord un message.",
"sessionFolderNeedsWorkspace": "Ouvrez d'abord un dossier d'espace de travail.",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "Cet agent n'expose aucun mode.",
"noSwitchTarget": "Aucun mode vers lequel basculer (mode Plan ou accès complet introuvable)."
},
+ "label": "Boule flottante",
+ "panelTitle": "Actions rapides",
+ "settingsTitle": "Boule flottante",
+ "close": "Fermer",
+ "resetPosition": "Réinitialiser la position",
+ "cheatSheetTitle": "Gestes",
+ "hint": "Faites glisser la boule pour la déplacer. Un balayage rapide déclenche un geste, un appui long ouvre ce panneau.",
+ "favoriteAgentsEmpty": "Aucun agent disponible",
"recentSessionDepth": "Profondeur des sessions récentes",
"bindingCleared": "Non attribué"
}
diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json
index d7e7556308..65081f0b20 100644
--- a/src/i18n/messages/ja.json
+++ b/src/i18n/messages/ja.json
@@ -181,13 +181,6 @@
"sectionDescription": "会話エリア内の折りたたみ/展開、ツール呼び出し、作業状態などのアニメーションとスムーズスクロールを制御します。オフにすると即時に更新されます。スピナーは回転し続けます。",
"enable": "チャットのアニメーションを有効にする"
},
- "messageNav": {
- "sectionTitle": "メッセージナビ",
- "sectionDescription": "会話のメッセージナビの位置。右下を選ぶと、ユーザーの発話ごとに 1 行のコンパクトなカードになり、入力欄の上に表示されます。",
- "positionStart": "左上(既定)",
- "positionBottomEnd": "右下(コンパクト)",
- "hint": "プランパネルとサブエージェントパネルは常に左上に残ります。"
- },
"chatWidth": {
"sectionTitle": "チャット幅",
"sectionDescription": "会話列と入力欄の最大幅です。チャット領域の左右の端をドラッグして調整することもできます。",
@@ -247,54 +240,6 @@
"credit": "画像提供 wallhaven.cc · SFW のみ"
}
},
- "floatingBall": {
- "sectionTitle": "フローティングボール",
- "sectionDescription": "ワークスペース上に置くドラッグ可能なボール。スワイプをショートカットに変えます。キーボードのないスマートフォン向けです。",
- "enable": "フローティングボールを表示",
- "hint": "ドラッグで移動、素早いスワイプでジェスチャー、長押しでパネルとジェスチャー一覧を開きます。",
- "resetPosition": "位置をリセット",
- "ballSize": "ボールサイズ",
- "sizeSmall": "小",
- "sizeMedium": "中",
- "sizeLarge": "大",
- "gestureBindings": "ジェスチャー割り当て",
- "bindingCleared": "未割り当て",
- "favoriteAgents": "お気に入りエージェント",
- "favoriteAgentsHint": "2〜3個のエージェントを選ぶと、お気に入りジェスチャーで切り替えられます。",
- "favoriteAgentsEmpty": "利用可能なエージェントがありません",
- "panelTitle": "クイック操作"
- },
- "gestures": {
- "tap": "タップ",
- "doubleTap": "ダブルタップ",
- "longPress": "長押し",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ その後 ←",
- "upThenRight": "↑ その後 →",
- "upDown": "↑ その後 ↓",
- "leftThenRight": "← その後 →",
- "rightThenLeft": "→ その後 ←",
- "upLeftThenDown": "↖ その後 ↓",
- "upRightThenDown": "↗ その後 ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ その後 ↑",
- "upThenDownRight": "↑ その後 ↘",
- "downThenUpRight": "↓ その後 ↗",
- "rightThenUp": "→ その後 ↑",
- "rightThenDown": "→ その後 ↓",
- "downThenRight": "↓ その後 →",
- "downThenLeft": "↓ その後 ←",
- "downRightThenUp": "↘ その後 ↑",
- "downLeftThenUp": "↙ その後 ↑",
- "upLeftThenRight": "↖ その後 →",
- "upRightThenLeft": "↗ その後 ←"
- },
"actions": {
"newConversation": "新しい会話",
"toggleSidebar": "サイドバーの切り替え",
@@ -328,6 +273,54 @@
"focusModeSelector": "モード選択",
"togglePlanFullAccess": "Plan/フルアクセス切替",
"openCollaboration": "コラボレーション"
+ },
+ "gestures": {
+ "tap": "タップ",
+ "doubleTap": "ダブルタップ",
+ "longPress": "長押し",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ その後 ←",
+ "upThenRight": "↑ その後 →",
+ "upDown": "↑ その後 ↓",
+ "leftThenRight": "← その後 →",
+ "rightThenLeft": "→ その後 ←",
+ "upLeftThenDown": "↖ その後 ↓",
+ "upRightThenDown": "↗ その後 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ その後 ↑",
+ "upThenDownRight": "↑ その後 ↘",
+ "downThenUpRight": "↓ その後 ↗",
+ "rightThenUp": "→ その後 ↑",
+ "rightThenDown": "→ その後 ↓",
+ "downThenRight": "↓ その後 →",
+ "downThenLeft": "↓ その後 ←",
+ "downRightThenUp": "↘ その後 ↑",
+ "downLeftThenUp": "↙ その後 ↑",
+ "upLeftThenRight": "↖ その後 →",
+ "upRightThenLeft": "↗ その後 ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "フローティングボール",
+ "sectionDescription": "ワークスペース上に置くドラッグ可能なボール。スワイプをショートカットに変えます。キーボードのないスマートフォン向けです。",
+ "enable": "フローティングボールを表示",
+ "hint": "ドラッグで移動、素早いスワイプでジェスチャー、長押しでパネルとジェスチャー一覧を開きます。",
+ "resetPosition": "位置をリセット",
+ "ballSize": "ボールサイズ",
+ "sizeSmall": "小",
+ "sizeMedium": "中",
+ "sizeLarge": "大",
+ "gestureBindings": "ジェスチャー割り当て",
+ "bindingCleared": "未割り当て",
+ "favoriteAgents": "お気に入りエージェント",
+ "favoriteAgentsHint": "2〜3個のエージェントを選ぶと、お気に入りジェスチャーで切り替えられます。",
+ "favoriteAgentsEmpty": "利用可能なエージェントがありません",
+ "panelTitle": "クイック操作"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "KIRO_API_KEY として CLI に渡されます。空欄なら kiro-cli login でサインインしたアカウントを使います。ブラウザでサインインできない環境(サーバー、Docker)でのみ必要です。",
"saveConfig": "Kiro 設定を保存"
},
+ "trae": {
+ "configManagement": "設定管理",
+ "configDescription": "TRAE CLI 2.0 は TRAE エンタープライズ版のフラッグシッププランのお客様のみ利用できます。Codeg はインストール済みの traecli を実行し、サインイン情報・スキル・MCP サーバーは ~/.trae に保存されます。モデル、モード、推論レベルはここにはありません。TRAE CLI が ACP で報告するため、入力欄のセレクターがセッションごとに管理します。",
+ "signInTitle": "サインイン",
+ "signInHint": "ターミナルでこのコマンドを一度実行し、エンタープライズ SSO でサインインしてください。Codeg のセッションはそのサインインを再利用します。",
+ "copyCommand": "コマンドをコピー",
+ "commandCopied": "コマンドをコピーしました",
+ "patLabel": "個人アクセストークン(任意)",
+ "patHint": "サーバーや Docker など、ブラウザでサインインできないマシン向けです。Codeg は TRAECLI_PERSONAL_ACCESS_TOKEN として TRAE CLI に渡し、セッション開始時にこのトークンでサインインします。空欄なら traecli login のサインインを使います。",
+ "hostLabel": "エンタープライズ API URL(任意)",
+ "hostHint": "組織が独自ドメインで TRAE を運用している場合のみ入力します。TRAECLI_HOST として渡されます。空欄なら TRAE の公式サービスを使います。",
+ "saveConfig": "TRAE CLI 設定を保存"
+ },
+ "commandCode": {
+ "configManagement": "設定管理",
+ "configDescription": "Codeg は command-code npm パッケージの Command Code CLI を実行し、サインイン情報・スキル・MCP サーバーは ~/.commandcode に保存されます。モデル、モード、推論レベルはここにはありません。Command Code が ACP で報告するため、入力欄のセレクターがセッションごとに管理します。",
+ "signInTitle": "サインイン",
+ "signInHint": "ターミナルでこのコマンドを一度実行し、Command Code アカウントでサインインしてください。Codeg のセッションはそのサインインを再利用します。",
+ "copyCommand": "コマンドをコピー",
+ "commandCopied": "コマンドをコピーしました",
+ "apiKeyLabel": "API キー(任意)",
+ "apiKeyHint": "サーバーや Docker など、ブラウザでサインインできないマシン向けです。COMMAND_CODE_API_KEY として Command Code に渡され、command-code login のサインインより優先されます。空欄ならそのサインインを使います。",
+ "saveConfig": "Command Code 設定を保存"
+ },
"deepseek": {
"configManagement": "DeepSeek Harness の設定",
"configDescription": "エンドポイントと API キーは deepseek-acp が起動時に読み込む環境変数です。モデルと推論レベルはセッションごとのセレクターなので、入力欄で切り替えます。",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Kiro 設定を保存しました",
"saveKiroFailed": "Kiro 設定の保存に失敗しました",
+ "traeSaved": "TRAE CLI 設定を保存しました",
+ "saveTraeFailed": "TRAE CLI 設定の保存に失敗しました",
+ "commandCodeSaved": "Command Code 設定を保存しました",
+ "saveCommandCodeFailed": "Command Code 設定の保存に失敗しました",
"systemAgentAlreadyLatest": "{name} は最新です({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "コミット"
},
"noFolderTitle": "開いているフォルダがありません",
- "noFolderHint": "フォルダを開くとここに表示されます"
+ "noFolderHint": "フォルダを開くとここに表示されます",
+ "openFullPage": "フルページで開く",
+ "back": "戻る",
+ "noAutomations": "このプロジェクトにはまだオートメーションがありません"
},
"windowControls": {
"minimizeWindow": "ウィンドウを最小化",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "何でも質問してください...",
+ "promptSuggestion": "{suggestion}(Tab で入力)",
"removeAttachmentAria": "{name} を削除",
"attachFiles": "ファイルを添付",
"addActions": "追加",
@@ -3395,6 +3420,10 @@
"searchModelAria": "モデルを検索",
"modelListLabel": "モデル",
"recommendedBadge": "推奨",
+ "recommendedValue": "推奨: {value}",
+ "searchOptions": "オプションを検索...",
+ "searchOptionsAria": "オプションを検索",
+ "noOptions": "オプションが見つかりません",
"noModels": "モデルが見つかりません",
"cancel": "キャンセル",
"send": "送信",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "メッセージナビ",
- "collapse": "メッセージナビを閉じる",
"loadingEarlier": "以前のメッセージを読み込み中…",
"loadEarlier": "以前のメッセージを読み込む",
- "collapsedSummary": "メッセージ {count}",
"fileCount": "{count, plural, one {# 個のファイル} other {# 個のファイル}}",
- "remove": "削除",
- "noDiffDataAvailable": "{filePath} の差分データがありません"
+ "subAgentCount": "{count, plural, one {# 個のサブエージェント} other {# 個のサブエージェント}}",
+ "showDiff": "{filePath} の変更を表示",
+ "hideDiff": "{filePath} の変更を隠す",
+ "openFile": "{filePath} を開く",
+ "collapse": "折りたたむ",
+ "currentMessage": "現在のメッセージ",
+ "scrollToCurrent": "現在のメッセージ(#{ordinal})へスクロール"
},
"replyArtifacts": {
"title": "変更されたファイル",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "タスク {task} を再開中",
"resumeDelegationNoId": "委任タスクを再開中",
"promptLabel": "プロンプト",
+ "ackRecorded": "作業タスクに記録しました",
+ "ackNotRecorded": "作業タスクに記録されていません",
+ "ackNotRecordedWithReason": "作業タスクに記録されていません: {reason}",
"verdict": {
"success": "成功",
"needs_review": "要確認",
@@ -4188,6 +4223,18 @@
"stopDeclined": "このタスクは停止できませんでした。すでに終了している可能性があります。",
"stopFailed": "タスクの停止に失敗しました: {error}"
},
+ "remoteControl": {
+ "title": "リモートコントロール有効",
+ "open": "ブラウザで開く",
+ "copy": "リンクをコピー",
+ "copied": "コピーしました",
+ "qr": "QR コード",
+ "qrLabel": "このセッションのリモートコントロール用リンクの QR コード",
+ "qrHint": "スマートフォンでスキャンすると、Claude アプリまたは claude.ai/code でこのセッションを続けられます。",
+ "noUrl": "Claude Code はこのセッションのリンクを返しませんでした",
+ "turnOff": "オフにする",
+ "turnOffBusy": "Claude の作業が終わると使えます"
+ },
"proposedPlan": {
"title": "提案された計画",
"planning": "計画中…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "フローティングボール",
- "panelTitle": "クイック操作",
- "settingsTitle": "フローティングボール",
- "close": "閉じる",
- "resetPosition": "位置をリセット",
- "cheatSheetTitle": "ジェスチャー",
- "hint": "ボールをドラッグして移動します。素早くスワイプするとジェスチャー、長押しでこのパネルが開きます。",
"actions": {
"newConversation": "新しい会話",
"toggleSidebar": "サイドバーの切り替え",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ その後 →",
"upRightThenLeft": "↗ その後 ←"
},
- "favoriteAgentsEmpty": "利用可能なエージェントがありません",
"toasts": {
"renameNeedsSavedSession": "名前の変更は保存済みセッションのみ有効です。まずメッセージを送信してください。",
"sessionFolderNeedsWorkspace": "先にワークスペースフォルダを開いてください。",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "このエージェントには利用可能なモードがありません。",
"noSwitchTarget": "切り替え先のモードがありません(Plan または完全アクセスモードが見つかりません)。"
},
+ "label": "フローティングボール",
+ "panelTitle": "クイック操作",
+ "settingsTitle": "フローティングボール",
+ "close": "閉じる",
+ "resetPosition": "位置をリセット",
+ "cheatSheetTitle": "ジェスチャー",
+ "hint": "ボールをドラッグして移動します。素早くスワイプするとジェスチャー、長押しでこのパネルが開きます。",
+ "favoriteAgentsEmpty": "利用可能なエージェントがありません",
"recentSessionDepth": "最近セッション切替数",
"bindingCleared": "未割り当て"
}
diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json
index 6819fb8e8d..ace14b54c7 100644
--- a/src/i18n/messages/ko.json
+++ b/src/i18n/messages/ko.json
@@ -181,13 +181,6 @@
"sectionDescription": "대화 영역의 접기/펼치기, 도구 호출, 작업 상태 등의 애니메이션과 부드러운 스크롤을 제어합니다. 끄면 즉시 갱신됩니다. 스피너는 계속 회전합니다.",
"enable": "채팅 애니메이션 사용"
},
- "messageNav": {
- "sectionTitle": "메시지 탐색기",
- "sectionDescription": "대화 메시지 탐색기의 위치입니다. 오른쪽 아래를 선택하면 사용자 발화마다 한 줄인 컴팩트 카드로 입력창 위에 표시됩니다.",
- "positionStart": "왼쪽 위(기본)",
- "positionBottomEnd": "오른쪽 아래(컴팩트)",
- "hint": "계획 및 하위 에이전트 패널은 항상 왼쪽 위에 남습니다."
- },
"chatWidth": {
"sectionTitle": "채팅 너비",
"sectionDescription": "대화 영역과 입력창의 최대 너비입니다. 채팅 영역의 좌우 가장자리를 드래그해서 조정할 수도 있습니다.",
@@ -247,54 +240,6 @@
"credit": "이미지 제공 wallhaven.cc · SFW만 표시"
}
},
- "floatingBall": {
- "sectionTitle": "플로팅 볼",
- "sectionDescription": "작업 공간 위의 드래그 가능한 볼로, 스와이프를 단축키로 바꿉니다. 키보드가 없는 휴대폰을 위한 기능입니다.",
- "enable": "플로팅 볼 표시",
- "hint": "드래그로 이동, 빠른 스와이프로 제스처, 길게 눌러 패널과 제스처 목록을 엽니다.",
- "resetPosition": "위치 초기화",
- "ballSize": "공 크기",
- "sizeSmall": "작게",
- "sizeMedium": "보통",
- "sizeLarge": "크게",
- "gestureBindings": "제스처 바인딩",
- "bindingCleared": "미지정",
- "favoriteAgents": "즐겨쓰는 에이전트",
- "favoriteAgentsHint": "2~3개의 에이전트를 선택하면 즐겨쓰기 제스처로 순환 전환됩니다.",
- "favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다",
- "panelTitle": "빠른 작업"
- },
- "gestures": {
- "tap": "탭",
- "doubleTap": "더블 탭",
- "longPress": "길게 누름",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ 후 ←",
- "upThenRight": "↑ 후 →",
- "upDown": "↑ 후 ↓",
- "leftThenRight": "← 후 →",
- "rightThenLeft": "→ 후 ←",
- "upLeftThenDown": "↖ 후 ↓",
- "upRightThenDown": "↗ 후 ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ 후 ↑",
- "upThenDownRight": "↑ 후 ↘",
- "downThenUpRight": "↓ 후 ↗",
- "rightThenUp": "→ 후 ↑",
- "rightThenDown": "→ 후 ↓",
- "downThenRight": "↓ 후 →",
- "downThenLeft": "↓ 후 ←",
- "downRightThenUp": "↘ 후 ↑",
- "downLeftThenUp": "↙ 후 ↑",
- "upLeftThenRight": "↖ 후 →",
- "upRightThenLeft": "↗ 후 ←"
- },
"actions": {
"newConversation": "새 대화",
"toggleSidebar": "사이드바 전환",
@@ -328,6 +273,54 @@
"focusModeSelector": "모드 선택",
"togglePlanFullAccess": "Plan/전체 권한 전환",
"openCollaboration": "협업"
+ },
+ "gestures": {
+ "tap": "탭",
+ "doubleTap": "더블 탭",
+ "longPress": "길게 누름",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 후 ←",
+ "upThenRight": "↑ 후 →",
+ "upDown": "↑ 후 ↓",
+ "leftThenRight": "← 후 →",
+ "rightThenLeft": "→ 후 ←",
+ "upLeftThenDown": "↖ 후 ↓",
+ "upRightThenDown": "↗ 후 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 후 ↑",
+ "upThenDownRight": "↑ 후 ↘",
+ "downThenUpRight": "↓ 후 ↗",
+ "rightThenUp": "→ 후 ↑",
+ "rightThenDown": "→ 후 ↓",
+ "downThenRight": "↓ 후 →",
+ "downThenLeft": "↓ 후 ←",
+ "downRightThenUp": "↘ 후 ↑",
+ "downLeftThenUp": "↙ 후 ↑",
+ "upLeftThenRight": "↖ 후 →",
+ "upRightThenLeft": "↗ 후 ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "플로팅 볼",
+ "sectionDescription": "작업 공간 위의 드래그 가능한 볼로, 스와이프를 단축키로 바꿉니다. 키보드가 없는 휴대폰을 위한 기능입니다.",
+ "enable": "플로팅 볼 표시",
+ "hint": "드래그로 이동, 빠른 스와이프로 제스처, 길게 눌러 패널과 제스처 목록을 엽니다.",
+ "resetPosition": "위치 초기화",
+ "ballSize": "공 크기",
+ "sizeSmall": "작게",
+ "sizeMedium": "보통",
+ "sizeLarge": "크게",
+ "gestureBindings": "제스처 바인딩",
+ "bindingCleared": "미지정",
+ "favoriteAgents": "즐겨쓰는 에이전트",
+ "favoriteAgentsHint": "2~3개의 에이전트를 선택하면 즐겨쓰기 제스처로 순환 전환됩니다.",
+ "favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다",
+ "panelTitle": "빠른 작업"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "KIRO_API_KEY로 CLI에 전달됩니다. 비워 두면 kiro-cli login으로 로그인한 계정을 사용합니다. 브라우저 로그인이 불가능한 환경(서버, Docker)에서만 필요합니다.",
"saveConfig": "Kiro 구성 저장"
},
+ "trae": {
+ "configManagement": "구성 관리",
+ "configDescription": "TRAE CLI 2.0은 TRAE 엔터프라이즈 플래그십 요금제 고객만 사용할 수 있습니다. Codeg는 설치된 traecli를 실행하며, 로그인 정보·스킬·MCP 서버는 ~/.trae에 저장됩니다. 모델, 모드, 추론 강도는 여기에 없습니다. TRAE CLI가 ACP로 보고하므로 입력창의 선택기가 세션별로 관리합니다.",
+ "signInTitle": "로그인",
+ "signInHint": "터미널에서 이 명령을 한 번 실행해 엔터프라이즈 SSO로 로그인하세요. Codeg의 세션은 그 로그인을 재사용합니다.",
+ "copyCommand": "명령 복사",
+ "commandCopied": "명령을 복사했습니다",
+ "patLabel": "개인 액세스 토큰(선택)",
+ "patHint": "서버나 Docker처럼 브라우저 로그인이 불가능한 머신용입니다. Codeg는 TRAECLI_PERSONAL_ACCESS_TOKEN으로 TRAE CLI에 전달하고 세션을 시작할 때마다 이 토큰으로 로그인합니다. 비워 두면 traecli login의 로그인을 사용합니다.",
+ "hostLabel": "엔터프라이즈 API URL(선택)",
+ "hostHint": "조직이 자체 도메인에서 TRAE를 운영하는 경우에만 입력하세요. TRAECLI_HOST로 전달되며, 비워 두면 TRAE 공식 서비스를 사용합니다.",
+ "saveConfig": "TRAE CLI 구성 저장"
+ },
+ "commandCode": {
+ "configManagement": "구성 관리",
+ "configDescription": "Codeg는 command-code npm 패키지의 Command Code CLI를 실행하며, 로그인 정보·스킬·MCP 서버는 ~/.commandcode에 저장됩니다. 모델, 모드, 추론 강도는 여기에 없습니다. Command Code가 ACP로 보고하므로 입력창의 선택기가 세션별로 관리합니다.",
+ "signInTitle": "로그인",
+ "signInHint": "터미널에서 이 명령을 한 번 실행해 Command Code 계정으로 로그인하세요. Codeg의 세션은 그 로그인을 재사용합니다.",
+ "copyCommand": "명령 복사",
+ "commandCopied": "명령을 복사했습니다",
+ "apiKeyLabel": "API 키(선택)",
+ "apiKeyHint": "서버나 Docker처럼 브라우저 로그인이 불가능한 머신용입니다. COMMAND_CODE_API_KEY로 Command Code에 전달되며 command-code login의 로그인보다 우선합니다. 비워 두면 그 로그인을 사용합니다.",
+ "saveConfig": "Command Code 구성 저장"
+ },
"deepseek": {
"configManagement": "DeepSeek Harness 구성",
"configDescription": "엔드포인트와 API 키는 deepseek-acp가 시작할 때 읽는 환경 변수입니다. 모델과 추론 강도는 세션별 선택기이므로 입력창에서 바꿉니다.",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Kiro 구성을 저장했습니다",
"saveKiroFailed": "Kiro 구성을 저장하지 못했습니다",
+ "traeSaved": "TRAE CLI 구성을 저장했습니다",
+ "saveTraeFailed": "TRAE CLI 구성을 저장하지 못했습니다",
+ "commandCodeSaved": "Command Code 구성을 저장했습니다",
+ "saveCommandCodeFailed": "Command Code 구성을 저장하지 못했습니다",
"systemAgentAlreadyLatest": "{name}은(는) 이미 최신 버전입니다({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "커밋"
},
"noFolderTitle": "열린 폴더 없음",
- "noFolderHint": "폴더를 열면 여기에 표시됩니다"
+ "noFolderHint": "폴더를 열면 여기에 표시됩니다",
+ "openFullPage": "전체 페이지에서 열기",
+ "back": "뒤로",
+ "noAutomations": "이 프로젝트에는 아직 자동화가 없습니다"
},
"windowControls": {
"minimizeWindow": "창 최소화",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "무엇이든 물어보세요...",
+ "promptSuggestion": "{suggestion} (Tab 키로 입력)",
"removeAttachmentAria": "{name} 제거",
"attachFiles": "파일 첨부",
"addActions": "추가",
@@ -3395,6 +3420,10 @@
"searchModelAria": "모델 검색",
"modelListLabel": "모델",
"recommendedBadge": "권장",
+ "recommendedValue": "권장: {value}",
+ "searchOptions": "옵션 검색...",
+ "searchOptionsAria": "옵션 검색",
+ "noOptions": "옵션을 찾을 수 없습니다",
"noModels": "모델을 찾을 수 없습니다",
"cancel": "취소",
"send": "보내기",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "메시지 탐색",
- "collapse": "메시지 탐색 접기",
"loadingEarlier": "이전 메시지를 불러오는 중…",
"loadEarlier": "이전 메시지 불러오기",
- "collapsedSummary": "메시지 {count}",
"fileCount": "{count, plural, one {#개 파일} other {#개 파일}}",
- "remove": "제거",
- "noDiffDataAvailable": "{filePath}에 대한 diff 데이터가 없습니다"
+ "subAgentCount": "{count, plural, one {서브 에이전트 #개} other {서브 에이전트 #개}}",
+ "showDiff": "{filePath}의 변경 사항 보기",
+ "hideDiff": "{filePath}의 변경 사항 숨기기",
+ "openFile": "{filePath} 열기",
+ "collapse": "접기",
+ "currentMessage": "현재 메시지",
+ "scrollToCurrent": "현재 메시지(#{ordinal})로 스크롤"
},
"replyArtifacts": {
"title": "변경된 파일",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "작업 {task} 재개 중",
"resumeDelegationNoId": "위임 작업 재개 중",
"promptLabel": "프롬프트",
+ "ackRecorded": "작업 항목에 기록됨",
+ "ackNotRecorded": "작업 항목에 기록되지 않음",
+ "ackNotRecordedWithReason": "작업 항목에 기록되지 않음: {reason}",
"verdict": {
"success": "성공",
"needs_review": "검토 필요",
@@ -4188,6 +4223,18 @@
"stopDeclined": "해당 작업을 중지할 수 없습니다. 이미 완료되었을 수 있습니다.",
"stopFailed": "작업 중지에 실패했습니다: {error}"
},
+ "remoteControl": {
+ "title": "원격 제어 켜짐",
+ "open": "브라우저에서 열기",
+ "copy": "링크 복사",
+ "copied": "복사됨",
+ "qr": "QR 코드",
+ "qrLabel": "이 세션의 원격 제어 링크 QR 코드",
+ "qrHint": "휴대폰으로 스캔하면 Claude 앱이나 claude.ai/code에서 이 세션을 이어갈 수 있습니다.",
+ "noUrl": "Claude Code가 이 세션의 링크를 반환하지 않았습니다",
+ "turnOff": "끄기",
+ "turnOffBusy": "Claude가 작업을 마치면 사용할 수 있습니다"
+ },
"proposedPlan": {
"title": "제안된 계획",
"planning": "계획 중…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "플로팅 볼",
- "panelTitle": "빠른 작업",
- "settingsTitle": "플로팅 볼",
- "close": "닫기",
- "resetPosition": "위치 초기화",
- "cheatSheetTitle": "제스처",
- "hint": "볼을 드래그해 이동하세요. 빠르게 스와이프하면 제스처, 길게 누르면 이 패널이 열립니다.",
"actions": {
"newConversation": "새 대화",
"toggleSidebar": "사이드바 전환",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ 후 →",
"upRightThenLeft": "↗ 후 ←"
},
- "favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다",
"toasts": {
"renameNeedsSavedSession": "이름 바꾸기는 저장된 세션에만 적용됩니다. 먼저 메시지를 보내세요.",
"sessionFolderNeedsWorkspace": "먼저 작업 공간 폴더를 여세요.",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "이 에이전트에는 사용 가능한 모드가 없습니다.",
"noSwitchTarget": "전환할 모드가 없습니다(Plan 또는 전체 접근 모드를 찾을 수 없음)."
},
+ "label": "플로팅 볼",
+ "panelTitle": "빠른 작업",
+ "settingsTitle": "플로팅 볼",
+ "close": "닫기",
+ "resetPosition": "위치 초기화",
+ "cheatSheetTitle": "제스처",
+ "hint": "볼을 드래그해 이동하세요. 빠르게 스와이프하면 제스처, 길게 누르면 이 패널이 열립니다.",
+ "favoriteAgentsEmpty": "사용 가능한 에이전트가 없습니다",
"recentSessionDepth": "최근 세션 전환 깊이",
"bindingCleared": "미지정"
}
diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json
index 9e1bc0c918..d4a6d6c288 100644
--- a/src/i18n/messages/pt.json
+++ b/src/i18n/messages/pt.json
@@ -181,13 +181,6 @@
"sectionDescription": "Animações de recolher/expandir, chamadas de ferramentas e estado de trabalho na área de conversa, além da rolagem suave. Desative para atualizações instantâneas. Os indicadores de carregamento continuam girando.",
"enable": "Ativar as animações do chat"
},
- "messageNav": {
- "sectionTitle": "Navegador de mensagens",
- "sectionDescription": "Posição do navegador de mensagens. No canto inferior direito vira um cartão compacto com uma linha por mensagem do usuário, acima do campo de entrada.",
- "positionStart": "Canto superior esquerdo (padrão)",
- "positionBottomEnd": "Canto inferior direito (compacto)",
- "hint": "Os painéis de plano e de subagentes permanecem no canto superior esquerdo."
- },
"chatWidth": {
"sectionTitle": "Largura do chat",
"sectionDescription": "Largura máxima da coluna de conversa e da caixa de entrada. Você também pode arrastar as bordas do chat para ajustá-la.",
@@ -247,54 +240,6 @@
"credit": "Imagens de wallhaven.cc · apenas SFW"
}
},
- "floatingBall": {
- "sectionTitle": "Bola flutuante",
- "sectionDescription": "Uma bola arrastável sobre o espaço de trabalho que transforma deslizes em atalhos — feita para o telefone, onde não há teclado.",
- "enable": "Mostrar bola flutuante",
- "hint": "Arraste para mover, deslize rápido para um gesto, toque e segure para o painel e a lista de gestos.",
- "resetPosition": "Redefinir posição",
- "ballSize": "Tamanho da bola",
- "sizeSmall": "Pequeno",
- "sizeMedium": "Médio",
- "sizeLarge": "Grande",
- "gestureBindings": "Atribuição de gestos",
- "bindingCleared": "Sem atribuição",
- "favoriteAgents": "Agentes favoritos",
- "favoriteAgentsHint": "Escolha 2-3 agentes para alternar com o gesto de favoritos.",
- "favoriteAgentsEmpty": "Nenhum agente disponível",
- "panelTitle": "Ações rápidas"
- },
- "gestures": {
- "tap": "Toque",
- "doubleTap": "Toque duplo",
- "longPress": "Pressão longa",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ depois ←",
- "upThenRight": "↑ depois →",
- "upDown": "↑ depois ↓",
- "leftThenRight": "← depois →",
- "rightThenLeft": "→ depois ←",
- "upLeftThenDown": "↖ depois ↓",
- "upRightThenDown": "↗ depois ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ depois ↑",
- "upThenDownRight": "↑ depois ↘",
- "downThenUpRight": "↓ depois ↗",
- "rightThenUp": "→ depois ↑",
- "rightThenDown": "→ depois ↓",
- "downThenRight": "↓ depois →",
- "downThenLeft": "↓ depois ←",
- "downRightThenUp": "↘ depois ↑",
- "downLeftThenUp": "↙ depois ↑",
- "upLeftThenRight": "↖ depois →",
- "upRightThenLeft": "↗ depois ←"
- },
"actions": {
"newConversation": "Nova conversa",
"toggleSidebar": "Alternar barra lateral",
@@ -328,6 +273,54 @@
"focusModeSelector": "Seletor de modo",
"togglePlanFullAccess": "Plano / acesso total",
"openCollaboration": "Colaboração"
+ },
+ "gestures": {
+ "tap": "Toque",
+ "doubleTap": "Toque duplo",
+ "longPress": "Pressão longa",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ depois ←",
+ "upThenRight": "↑ depois →",
+ "upDown": "↑ depois ↓",
+ "leftThenRight": "← depois →",
+ "rightThenLeft": "→ depois ←",
+ "upLeftThenDown": "↖ depois ↓",
+ "upRightThenDown": "↗ depois ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ depois ↑",
+ "upThenDownRight": "↑ depois ↘",
+ "downThenUpRight": "↓ depois ↗",
+ "rightThenUp": "→ depois ↑",
+ "rightThenDown": "→ depois ↓",
+ "downThenRight": "↓ depois →",
+ "downThenLeft": "↓ depois ←",
+ "downRightThenUp": "↘ depois ↑",
+ "downLeftThenUp": "↙ depois ↑",
+ "upLeftThenRight": "↖ depois →",
+ "upRightThenLeft": "↗ depois ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "Bola flutuante",
+ "sectionDescription": "Uma bola arrastável sobre o espaço de trabalho que transforma deslizes em atalhos — feita para o telefone, onde não há teclado.",
+ "enable": "Mostrar bola flutuante",
+ "hint": "Arraste para mover, deslize rápido para um gesto, toque e segure para o painel e a lista de gestos.",
+ "resetPosition": "Redefinir posição",
+ "ballSize": "Tamanho da bola",
+ "sizeSmall": "Pequeno",
+ "sizeMedium": "Médio",
+ "sizeLarge": "Grande",
+ "gestureBindings": "Atribuição de gestos",
+ "bindingCleared": "Sem atribuição",
+ "favoriteAgents": "Agentes favoritos",
+ "favoriteAgentsHint": "Escolha 2-3 agentes para alternar com o gesto de favoritos.",
+ "favoriteAgentsEmpty": "Nenhum agente disponível",
+ "panelTitle": "Ações rápidas"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "Passada à CLI como KIRO_API_KEY. Deixe vazia para usar a conta conectada via kiro-cli login; só é necessária onde não há login pelo navegador (servidores, Docker).",
"saveConfig": "Salvar configuração do Kiro"
},
+ "trae": {
+ "configManagement": "Configuração",
+ "configDescription": "O TRAE CLI 2.0 está disponível apenas para clientes do plano principal do TRAE Enterprise. O Codeg executa o traecli que você instalou, que guarda o login, as skills e os servidores MCP em ~/.trae. Modelo, modo e esforço de raciocínio não ficam aqui: o TRAE CLI os informa via ACP, então os seletores do compositor os gerenciam em cada sessão.",
+ "signInTitle": "Entrar",
+ "signInHint": "Execute isto uma vez em um terminal para entrar com o SSO da sua empresa. As sessões do Codeg reutilizam esse login.",
+ "copyCommand": "Copiar comando",
+ "commandCopied": "Comando copiado",
+ "patLabel": "Token de acesso pessoal (opcional)",
+ "patHint": "Para uma máquina em que não é possível entrar pelo navegador, como um servidor ou uma instalação Docker. O Codeg o passa ao TRAE CLI como TRAECLI_PERSONAL_ACCESS_TOKEN e entra com ele sempre que uma sessão começa. Deixe vazio para usar o login do traecli login.",
+ "hostLabel": "URL da API corporativa (opcional)",
+ "hostHint": "Somente se a sua organização executa o TRAE em um domínio próprio. É passada como TRAECLI_HOST; deixe vazia para usar o serviço do TRAE.",
+ "saveConfig": "Salvar configuração do TRAE CLI"
+ },
+ "commandCode": {
+ "configManagement": "Configuração",
+ "configDescription": "O Codeg executa a CLI do Command Code do pacote npm command-code, que guarda o login, as skills e os servidores MCP em ~/.commandcode. Modelo, modo e esforço de raciocínio não ficam aqui: o Command Code os informa via ACP, então os seletores do compositor os gerenciam em cada sessão.",
+ "signInTitle": "Entrar",
+ "signInHint": "Execute isto uma vez em um terminal para entrar com sua conta do Command Code. As sessões do Codeg reutilizam esse login.",
+ "copyCommand": "Copiar comando",
+ "commandCopied": "Comando copiado",
+ "apiKeyLabel": "Chave de API (opcional)",
+ "apiKeyHint": "Para uma máquina em que não é possível entrar pelo navegador, como um servidor ou uma instalação Docker. Passada ao Command Code como COMMAND_CODE_API_KEY, que tem prioridade sobre o login do command-code login. Deixe vazia para usar esse login.",
+ "saveConfig": "Salvar configuração do Command Code"
+ },
"deepseek": {
"configManagement": "Configuração do DeepSeek Harness",
"configDescription": "O endpoint e a chave são variáveis de ambiente que o deepseek-acp lê ao iniciar. O modelo e o nível de raciocínio são seletores por sessão — escolha-os no campo de mensagem.",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "Failed to save Antigravity config",
"kiroSaved": "Configuração do Kiro salva",
"saveKiroFailed": "Falha ao salvar a configuração do Kiro",
+ "traeSaved": "Configuração do TRAE CLI salva",
+ "saveTraeFailed": "Falha ao salvar a configuração do TRAE CLI",
+ "commandCodeSaved": "Configuração do Command Code salva",
+ "saveCommandCodeFailed": "Falha ao salvar a configuração do Command Code",
"systemAgentAlreadyLatest": "{name} já está atualizado ({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "Confirmações"
},
"noFolderTitle": "Nenhuma pasta aberta",
- "noFolderHint": "Abra uma pasta para ver seu conteúdo aqui"
+ "noFolderHint": "Abra uma pasta para ver seu conteúdo aqui",
+ "openFullPage": "Abrir em página inteira",
+ "back": "Voltar",
+ "noAutomations": "Este projeto ainda não tem automações"
},
"windowControls": {
"minimizeWindow": "Minimizar janela",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "Pergunte qualquer coisa...",
+ "promptSuggestion": "{suggestion} (Tab para usar)",
"removeAttachmentAria": "Remover {name}",
"attachFiles": "Anexar arquivos",
"addActions": "Adicionar",
@@ -3395,6 +3420,10 @@
"searchModelAria": "Buscar modelos",
"modelListLabel": "Modelos",
"recommendedBadge": "Recomendado",
+ "recommendedValue": "Recomendado: {value}",
+ "searchOptions": "Buscar opções...",
+ "searchOptionsAria": "Buscar opções",
+ "noOptions": "Nenhuma opção encontrada",
"noModels": "Nenhum modelo encontrado",
"cancel": "Cancelar",
"send": "Enviar",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "Navegação de mensagens",
- "collapse": "Recolher navegação de mensagens",
"loadingEarlier": "Carregando mensagens anteriores…",
"loadEarlier": "Carregar mensagens anteriores",
- "collapsedSummary": "Mensagens {count}",
"fileCount": "{count, plural, one {# arquivo} other {# arquivos}}",
- "remove": "Remover",
- "noDiffDataAvailable": "Nenhum dado de diff disponível para {filePath}"
+ "subAgentCount": "{count, plural, one {# subagente} other {# subagentes}}",
+ "showDiff": "Mostrar as alterações de {filePath}",
+ "hideDiff": "Ocultar as alterações de {filePath}",
+ "openFile": "Abrir {filePath}",
+ "collapse": "Recolher",
+ "currentMessage": "Mensagem atual",
+ "scrollToCurrent": "Rolar até a mensagem atual (#{ordinal})"
},
"replyArtifacts": {
"title": "Arquivos alterados",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "Retomando a tarefa {task}",
"resumeDelegationNoId": "Retomando uma tarefa delegada",
"promptLabel": "Instrução",
+ "ackRecorded": "Registrado na tarefa de trabalho",
+ "ackNotRecorded": "Não registrado na tarefa de trabalho",
+ "ackNotRecordedWithReason": "Não registrado na tarefa de trabalho: {reason}",
"verdict": {
"success": "sucesso",
"needs_review": "requer revisão",
@@ -4188,6 +4223,18 @@
"stopDeclined": "Não foi possível parar essa tarefa — ela pode já ter terminado.",
"stopFailed": "Falha ao parar a tarefa: {error}"
},
+ "remoteControl": {
+ "title": "Controle remoto ativado",
+ "open": "Abrir no navegador",
+ "copy": "Copiar link",
+ "copied": "Copiado",
+ "qr": "Código QR",
+ "qrLabel": "Código QR do link de controle remoto desta sessão",
+ "qrHint": "Escaneie com o celular para continuar esta sessão no app do Claude ou em claude.ai/code.",
+ "noUrl": "O Claude Code não retornou nenhum link para esta sessão",
+ "turnOff": "Desativar",
+ "turnOffBusy": "Disponível quando o Claude terminar"
+ },
"proposedPlan": {
"title": "Plano proposto",
"planning": "A planear…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "Bola flutuante",
- "panelTitle": "Ações rápidas",
- "settingsTitle": "Bola flutuante",
- "close": "Fechar",
- "resetPosition": "Redefinir posição",
- "cheatSheetTitle": "Gestos",
- "hint": "Arraste a bola para movê-la. Um deslize rápido dispara um gesto; um toque longo abre este painel.",
"actions": {
"newConversation": "Nova conversa",
"toggleSidebar": "Alternar barra lateral",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ depois →",
"upRightThenLeft": "↗ depois ←"
},
- "favoriteAgentsEmpty": "Nenhum agente disponível",
"toasts": {
"renameNeedsSavedSession": "Renomear só funciona em sessões salvas — envie uma mensagem primeiro.",
"sessionFolderNeedsWorkspace": "Abra antes uma pasta de espaço de trabalho.",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "Este agente não expõe nenhum modo.",
"noSwitchTarget": "Nenhum modo para alternar (modo Plan ou de acesso completo não encontrado)."
},
+ "label": "Bola flutuante",
+ "panelTitle": "Ações rápidas",
+ "settingsTitle": "Bola flutuante",
+ "close": "Fechar",
+ "resetPosition": "Redefinir posição",
+ "cheatSheetTitle": "Gestos",
+ "hint": "Arraste a bola para movê-la. Um deslize rápido dispara um gesto; um toque longo abre este painel.",
+ "favoriteAgentsEmpty": "Nenhum agente disponível",
"recentSessionDepth": "Profundidade de sessões recentes",
"bindingCleared": "Sem atribuição"
}
diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json
index db78c4acfc..5cd823eff0 100644
--- a/src/i18n/messages/zh-CN.json
+++ b/src/i18n/messages/zh-CN.json
@@ -181,13 +181,6 @@
"sectionDescription": "会话区域内的折叠/展开、工具调用、工作状态等动画,以及平滑滚动。关闭后界面立即更新、不再有过渡动画;加载转圈图标仍会旋转。",
"enable": "启用聊天区域动画"
},
- "messageNav": {
- "sectionTitle": "消息导航",
- "sectionDescription": "会话消息导航卡的位置。右下角会变成紧凑卡片:每次用户回话一行,贴在输入框上方,不挡阅读区。",
- "positionStart": "左上(默认)",
- "positionBottomEnd": "右下(紧凑)",
- "hint": "计划面板与子智能体面板始终留在左上。"
- },
"chatWidth": {
"sectionTitle": "聊天区域宽度",
"sectionDescription": "会话列与输入框的最大宽度。也可以直接拖动聊天区域左右两侧的边缘来调整。",
@@ -247,54 +240,6 @@
"credit": "图片来源 wallhaven.cc · 仅 SFW 内容"
}
},
- "floatingBall": {
- "sectionTitle": "悬浮球",
- "sectionDescription": "工作区上的可拖动悬浮球,把滑动手势变成快捷键——为没有键盘的手机而设。",
- "enable": "显示悬浮球",
- "hint": "拖动可移动;快速滑动触发手势;长按打开面板与手势表。",
- "resetPosition": "重置位置",
- "ballSize": "球体大小",
- "sizeSmall": "小",
- "sizeMedium": "中",
- "sizeLarge": "大",
- "gestureBindings": "手势绑定",
- "bindingCleared": "未绑定",
- "favoriteAgents": "常用智能体",
- "favoriteAgentsHint": "选择 2-3 个智能体,供「常用智能体」手势循环快切。",
- "favoriteAgentsEmpty": "暂无可用智能体",
- "panelTitle": "快捷操作"
- },
- "gestures": {
- "tap": "单击",
- "doubleTap": "双击",
- "longPress": "长按",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ 然后 ←",
- "upThenRight": "↑ 然后 →",
- "upDown": "↑ 然后 ↓",
- "leftThenRight": "← 然后 →",
- "rightThenLeft": "→ 然后 ←",
- "upLeftThenDown": "↖ 然后 ↓",
- "upRightThenDown": "↗ 然后 ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ 然后 ↑",
- "upThenDownRight": "↑ 然后 ↘",
- "downThenUpRight": "↓ 然后 ↗",
- "rightThenUp": "→ 然后 ↑",
- "rightThenDown": "→ 然后 ↓",
- "downThenRight": "↓ 然后 →",
- "downThenLeft": "↓ 然后 ←",
- "downRightThenUp": "↘ 然后 ↑",
- "downLeftThenUp": "↙ 然后 ↑",
- "upLeftThenRight": "↖ 然后 →",
- "upRightThenLeft": "↗ 然后 ←"
- },
"actions": {
"newConversation": "新建会话",
"toggleSidebar": "切换侧栏",
@@ -328,6 +273,54 @@
"focusModeSelector": "模式选择",
"togglePlanFullAccess": "Plan/全权限切换",
"openCollaboration": "协作"
+ },
+ "gestures": {
+ "tap": "单击",
+ "doubleTap": "双击",
+ "longPress": "长按",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 然后 ←",
+ "upThenRight": "↑ 然后 →",
+ "upDown": "↑ 然后 ↓",
+ "leftThenRight": "← 然后 →",
+ "rightThenLeft": "→ 然后 ←",
+ "upLeftThenDown": "↖ 然后 ↓",
+ "upRightThenDown": "↗ 然后 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 然后 ↑",
+ "upThenDownRight": "↑ 然后 ↘",
+ "downThenUpRight": "↓ 然后 ↗",
+ "rightThenUp": "→ 然后 ↑",
+ "rightThenDown": "→ 然后 ↓",
+ "downThenRight": "↓ 然后 →",
+ "downThenLeft": "↓ 然后 ←",
+ "downRightThenUp": "↘ 然后 ↑",
+ "downLeftThenUp": "↙ 然后 ↑",
+ "upLeftThenRight": "↖ 然后 →",
+ "upRightThenLeft": "↗ 然后 ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "悬浮球",
+ "sectionDescription": "工作区上的可拖动悬浮球,把滑动手势变成快捷键——为没有键盘的手机而设。",
+ "enable": "显示悬浮球",
+ "hint": "拖动可移动;快速滑动触发手势;长按打开面板与手势表。",
+ "resetPosition": "重置位置",
+ "ballSize": "球体大小",
+ "sizeSmall": "小",
+ "sizeMedium": "中",
+ "sizeLarge": "大",
+ "gestureBindings": "手势绑定",
+ "bindingCleared": "未绑定",
+ "favoriteAgents": "常用智能体",
+ "favoriteAgentsHint": "选择 2-3 个智能体,供「常用智能体」手势循环快切。",
+ "favoriteAgentsEmpty": "暂无可用智能体",
+ "panelTitle": "快捷操作"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "以 KIRO_API_KEY 传给 CLI。留空则使用 kiro-cli login 登录的账号;只有无法用浏览器登录的环境(服务器、Docker)才需要 API Key。",
"saveConfig": "保存 Kiro 配置"
},
+ "trae": {
+ "configManagement": "配置管理",
+ "configDescription": "TRAE CLI 2.0 仅向 TRAE 企业版旗舰版套餐客户开放。Codeg 运行你安装的 traecli,它把登录状态、技能和 MCP 服务器保存在 ~/.trae 中。模型、模式和推理强度不在这里设置:TRAE CLI 会通过 ACP 上报它们,由输入框自带的选择器按会话管理。",
+ "signInTitle": "登录",
+ "signInHint": "在终端中运行一次下面的命令,用企业 SSO 登录。Codeg 里的会话会复用这次登录。",
+ "copyCommand": "复制命令",
+ "commandCopied": "命令已复制",
+ "patLabel": "个人访问令牌(可选)",
+ "patHint": "适用于无法用浏览器登录的机器,例如服务器或 Docker 部署。Codeg 会以 TRAECLI_PERSONAL_ACCESS_TOKEN 传给 TRAE CLI,并在每次启动会话时用它登录。留空则使用 traecli login 的登录。",
+ "hostLabel": "企业 API 地址(可选)",
+ "hostHint": "仅当你的组织在自有域名上部署 TRAE 时填写。以 TRAECLI_HOST 传入;留空则使用 TRAE 官方服务。",
+ "saveConfig": "保存 TRAE CLI 配置"
+ },
+ "commandCode": {
+ "configManagement": "配置管理",
+ "configDescription": "Codeg 运行 command-code npm 包提供的 Command Code CLI,它把登录状态、技能和 MCP 服务器保存在 ~/.commandcode 中。模型、模式和推理强度不在这里设置:Command Code 会通过 ACP 上报它们,由输入框自带的选择器按会话管理。",
+ "signInTitle": "登录",
+ "signInHint": "在终端中运行一次下面的命令,登录你的 Command Code 账号。Codeg 里的会话会复用这次登录。",
+ "copyCommand": "复制命令",
+ "commandCopied": "命令已复制",
+ "apiKeyLabel": "API 密钥(可选)",
+ "apiKeyHint": "适用于无法用浏览器登录的机器,例如服务器或 Docker 部署。以 COMMAND_CODE_API_KEY 传给 Command Code,优先于 command-code login 的登录。留空则使用那次登录。",
+ "saveConfig": "保存 Command Code 配置"
+ },
"deepseek": {
"configManagement": "DeepSeek Harness 配置",
"configDescription": "端点与密钥是 deepseek-acp 启动时读取的环境变量。模型和推理档位是会话级选择器,在输入框里切换。",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "保存 Antigravity 配置失败",
"kiroSaved": "Kiro 配置已保存",
"saveKiroFailed": "保存 Kiro 配置失败",
+ "traeSaved": "TRAE CLI 配置已保存",
+ "saveTraeFailed": "保存 TRAE CLI 配置失败",
+ "commandCodeSaved": "Command Code 配置已保存",
+ "saveCommandCodeFailed": "保存 Command Code 配置失败",
"systemAgentAlreadyLatest": "{name} 已是最新版本({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "提交"
},
"noFolderTitle": "暂无打开的文件夹",
- "noFolderHint": "打开一个文件夹后在这里查看"
+ "noFolderHint": "打开一个文件夹后在这里查看",
+ "openFullPage": "在完整页面中打开",
+ "back": "返回",
+ "noAutomations": "此项目还没有自动化"
},
"windowControls": {
"minimizeWindow": "最小化窗口",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "请开始输入...",
+ "promptSuggestion": "{suggestion}(按 Tab 填入)",
"removeAttachmentAria": "移除 {name}",
"attachFiles": "附加文件",
"attachLocalUpload": "附加本地文件",
@@ -3397,6 +3422,10 @@
"searchModelAria": "搜索模型",
"modelListLabel": "模型",
"recommendedBadge": "推荐",
+ "recommendedValue": "推荐:{value}",
+ "searchOptions": "搜索选项...",
+ "searchOptionsAria": "搜索选项",
+ "noOptions": "未找到选项",
"noModels": "未找到模型",
"cancel": "取消",
"send": "发送",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "消息导航",
- "collapse": "收起消息导航",
"loadingEarlier": "正在加载更早的消息…",
"loadEarlier": "加载更早的消息",
- "collapsedSummary": "消息 {count}",
"fileCount": "{count} 个文件",
- "remove": "移除",
- "noDiffDataAvailable": "未找到 {filePath} 的差异数据"
+ "subAgentCount": "{count} 个子智能体",
+ "showDiff": "展开 {filePath} 的改动",
+ "hideDiff": "收起 {filePath} 的改动",
+ "openFile": "打开 {filePath}",
+ "collapse": "收起",
+ "currentMessage": "当前消息",
+ "scrollToCurrent": "滚动到当前消息(#{ordinal})"
},
"replyArtifacts": {
"title": "改动文件",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "恢复任务 {task}",
"resumeDelegationNoId": "恢复委派任务",
"promptLabel": "指令",
+ "ackRecorded": "已记录到待办任务",
+ "ackNotRecorded": "未记录到待办任务",
+ "ackNotRecordedWithReason": "未记录到待办任务:{reason}",
"verdict": {
"success": "成功",
"needs_review": "待复核",
@@ -4188,6 +4223,18 @@
"stopDeclined": "无法停止该任务,它可能已经结束。",
"stopFailed": "停止任务失败:{error}"
},
+ "remoteControl": {
+ "title": "远程控制已开启",
+ "open": "在浏览器中打开",
+ "copy": "复制链接",
+ "copied": "已复制",
+ "qr": "二维码",
+ "qrLabel": "本会话远程控制链接的二维码",
+ "qrHint": "用手机扫码,在 Claude App 或 claude.ai/code 上继续本会话。",
+ "noUrl": "Claude Code 没有返回本会话的链接",
+ "turnOff": "关闭",
+ "turnOffBusy": "Claude 完成当前工作后可用"
+ },
"proposedPlan": {
"title": "计划提案",
"planning": "规划中…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "悬浮球",
- "panelTitle": "快捷操作",
- "settingsTitle": "悬浮球",
- "close": "关闭",
- "resetPosition": "重置位置",
- "cheatSheetTitle": "手势",
- "hint": "拖动悬浮球可移动位置。快速滑动触发手势,长按打开此面板。",
"actions": {
"newConversation": "新建会话",
"toggleSidebar": "切换侧栏",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ 然后 →",
"upRightThenLeft": "↗ 然后 ←"
},
- "favoriteAgentsEmpty": "暂无可用智能体",
"toasts": {
"renameNeedsSavedSession": "重命名只对已保存的会话生效——先发一条消息。",
"sessionFolderNeedsWorkspace": "请先打开一个工作区文件夹。",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "该智能体没有可用模式。",
"noSwitchTarget": "没有可切换的模式(未找到 Plan 或完整访问模式)。"
},
+ "label": "悬浮球",
+ "panelTitle": "快捷操作",
+ "settingsTitle": "悬浮球",
+ "close": "关闭",
+ "resetPosition": "重置位置",
+ "cheatSheetTitle": "手势",
+ "hint": "拖动悬浮球可移动位置。快速滑动触发手势,长按打开此面板。",
+ "favoriteAgentsEmpty": "暂无可用智能体",
"recentSessionDepth": "最近会话切换深度",
"bindingCleared": "未绑定"
}
diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json
index 5abd210c9e..0b064127e8 100644
--- a/src/i18n/messages/zh-TW.json
+++ b/src/i18n/messages/zh-TW.json
@@ -181,13 +181,6 @@
"sectionDescription": "對話區域內的摺疊/展開、工具呼叫、工作狀態等動畫,以及平滑捲動。關閉後介面會立即更新、不再有過渡動畫;載入轉圈圖示仍會旋轉。",
"enable": "啟用聊天區域動畫"
},
- "messageNav": {
- "sectionTitle": "訊息導覽",
- "sectionDescription": "對話訊息導覽卡的位置。右下角會變成緊湊卡片:每次使用者回話一行,貼在輸入框上方,不擋閱讀區。",
- "positionStart": "左上(預設)",
- "positionBottomEnd": "右下(緊湊)",
- "hint": "計畫面板與子代理面板始終留在左上。"
- },
"chatWidth": {
"sectionTitle": "聊天區域寬度",
"sectionDescription": "對話列與輸入框的最大寬度。也可以直接拖曳聊天區域左右兩側的邊緣來調整。",
@@ -247,54 +240,6 @@
"credit": "圖片來源 wallhaven.cc · 僅 SFW 內容"
}
},
- "floatingBall": {
- "sectionTitle": "懸浮球",
- "sectionDescription": "工作區上的可拖動懸浮球,把滑動手勢變成快捷鍵——為沒有鍵盤的手機而設。",
- "enable": "顯示懸浮球",
- "hint": "拖動可移動;快速滑動觸發手勢;長按打開面板與手勢表。",
- "resetPosition": "重設位置",
- "ballSize": "球體大小",
- "sizeSmall": "小",
- "sizeMedium": "中",
- "sizeLarge": "大",
- "gestureBindings": "手勢綁定",
- "bindingCleared": "未綁定",
- "favoriteAgents": "常用代理人",
- "favoriteAgentsHint": "選擇 2-3 個代理人,供「常用代理人」手勢循環快切。",
- "favoriteAgentsEmpty": "暫無可用代理人",
- "panelTitle": "快捷操作"
- },
- "gestures": {
- "tap": "單擊",
- "doubleTap": "雙擊",
- "longPress": "長按",
- "left": "←",
- "right": "→",
- "up": "↑",
- "upLeft": "↖",
- "upRight": "↗",
- "upThenLeft": "↑ 然後 ←",
- "upThenRight": "↑ 然後 →",
- "upDown": "↑ 然後 ↓",
- "leftThenRight": "← 然後 →",
- "rightThenLeft": "→ 然後 ←",
- "upLeftThenDown": "↖ 然後 ↓",
- "upRightThenDown": "↗ 然後 ↓",
- "down": "↓",
- "downLeft": "↙",
- "downRight": "↘",
- "downUp": "↓ 然後 ↑",
- "upThenDownRight": "↑ 然後 ↘",
- "downThenUpRight": "↓ 然後 ↗",
- "rightThenUp": "→ 然後 ↑",
- "rightThenDown": "→ 然後 ↓",
- "downThenRight": "↓ 然後 →",
- "downThenLeft": "↓ 然後 ←",
- "downRightThenUp": "↘ 然後 ↑",
- "downLeftThenUp": "↙ 然後 ↑",
- "upLeftThenRight": "↖ 然後 →",
- "upRightThenLeft": "↗ 然後 ←"
- },
"actions": {
"newConversation": "新增對話",
"toggleSidebar": "切換側欄",
@@ -328,6 +273,54 @@
"focusModeSelector": "模式選擇",
"togglePlanFullAccess": "Plan/全權限切換",
"openCollaboration": "協作"
+ },
+ "gestures": {
+ "tap": "單擊",
+ "doubleTap": "雙擊",
+ "longPress": "長按",
+ "left": "←",
+ "right": "→",
+ "up": "↑",
+ "upLeft": "↖",
+ "upRight": "↗",
+ "upThenLeft": "↑ 然後 ←",
+ "upThenRight": "↑ 然後 →",
+ "upDown": "↑ 然後 ↓",
+ "leftThenRight": "← 然後 →",
+ "rightThenLeft": "→ 然後 ←",
+ "upLeftThenDown": "↖ 然後 ↓",
+ "upRightThenDown": "↗ 然後 ↓",
+ "down": "↓",
+ "downLeft": "↙",
+ "downRight": "↘",
+ "downUp": "↓ 然後 ↑",
+ "upThenDownRight": "↑ 然後 ↘",
+ "downThenUpRight": "↓ 然後 ↗",
+ "rightThenUp": "→ 然後 ↑",
+ "rightThenDown": "→ 然後 ↓",
+ "downThenRight": "↓ 然後 →",
+ "downThenLeft": "↓ 然後 ←",
+ "downRightThenUp": "↘ 然後 ↑",
+ "downLeftThenUp": "↙ 然後 ↑",
+ "upLeftThenRight": "↖ 然後 →",
+ "upRightThenLeft": "↗ 然後 ←"
+ },
+ "floatingBall": {
+ "sectionTitle": "懸浮球",
+ "sectionDescription": "工作區上的可拖動懸浮球,把滑動手勢變成快捷鍵——為沒有鍵盤的手機而設。",
+ "enable": "顯示懸浮球",
+ "hint": "拖動可移動;快速滑動觸發手勢;長按打開面板與手勢表。",
+ "resetPosition": "重設位置",
+ "ballSize": "球體大小",
+ "sizeSmall": "小",
+ "sizeMedium": "中",
+ "sizeLarge": "大",
+ "gestureBindings": "手勢綁定",
+ "bindingCleared": "未綁定",
+ "favoriteAgents": "常用代理人",
+ "favoriteAgentsHint": "選擇 2-3 個代理人,供「常用代理人」手勢循環快切。",
+ "favoriteAgentsEmpty": "暫無可用代理人",
+ "panelTitle": "快捷操作"
}
},
"SystemSettings": {
@@ -1201,6 +1194,30 @@
"apiKeyHint": "以 KIRO_API_KEY 傳給 CLI。留空則使用 kiro-cli login 登入的帳號;只有無法用瀏覽器登入的環境(伺服器、Docker)才需要 API Key。",
"saveConfig": "儲存 Kiro 設定"
},
+ "trae": {
+ "configManagement": "設定管理",
+ "configDescription": "TRAE CLI 2.0 僅開放給 TRAE 企業版旗艦版方案的客戶。Codeg 執行你安裝的 traecli,它把登入狀態、技能和 MCP 伺服器儲存在 ~/.trae 中。模型、模式和推理強度不在這裡設定:TRAE CLI 會透過 ACP 回報它們,由輸入框內建的選擇器依工作階段管理。",
+ "signInTitle": "登入",
+ "signInHint": "在終端機中執行一次下面的命令,用企業 SSO 登入。Codeg 裡的工作階段會沿用這次登入。",
+ "copyCommand": "複製命令",
+ "commandCopied": "命令已複製",
+ "patLabel": "個人存取權杖(選填)",
+ "patHint": "適用於無法用瀏覽器登入的機器,例如伺服器或 Docker 部署。Codeg 會以 TRAECLI_PERSONAL_ACCESS_TOKEN 傳給 TRAE CLI,並在每次啟動工作階段時用它登入。留空則使用 traecli login 的登入。",
+ "hostLabel": "企業 API 位址(選填)",
+ "hostHint": "僅當你的組織在自有網域上部署 TRAE 時填寫。以 TRAECLI_HOST 傳入;留空則使用 TRAE 官方服務。",
+ "saveConfig": "儲存 TRAE CLI 設定"
+ },
+ "commandCode": {
+ "configManagement": "設定管理",
+ "configDescription": "Codeg 執行 command-code npm 套件提供的 Command Code CLI,它把登入狀態、技能和 MCP 伺服器儲存在 ~/.commandcode 中。模型、模式和推理強度不在這裡設定:Command Code 會透過 ACP 回報它們,由輸入框內建的選擇器依工作階段管理。",
+ "signInTitle": "登入",
+ "signInHint": "在終端機中執行一次下面的命令,登入你的 Command Code 帳號。Codeg 裡的工作階段會沿用這次登入。",
+ "copyCommand": "複製命令",
+ "commandCopied": "命令已複製",
+ "apiKeyLabel": "API 金鑰(選填)",
+ "apiKeyHint": "適用於無法用瀏覽器登入的機器,例如伺服器或 Docker 部署。以 COMMAND_CODE_API_KEY 傳給 Command Code,優先於 command-code login 的登入。留空則使用那次登入。",
+ "saveConfig": "儲存 Command Code 設定"
+ },
"deepseek": {
"configManagement": "DeepSeek Harness 設定",
"configDescription": "端點與金鑰是 deepseek-acp 啟動時讀取的環境變數。模型與推理等級是工作階段層級的選擇器,在輸入框裡切換。",
@@ -1696,6 +1713,10 @@
"saveAntigravityConfigFailed": "保存 Antigravity 配置失败",
"kiroSaved": "Kiro 設定已儲存",
"saveKiroFailed": "儲存 Kiro 設定失敗",
+ "traeSaved": "TRAE CLI 設定已儲存",
+ "saveTraeFailed": "儲存 TRAE CLI 設定失敗",
+ "commandCodeSaved": "Command Code 設定已儲存",
+ "saveCommandCodeFailed": "儲存 Command Code 設定失敗",
"systemAgentAlreadyLatest": "{name} 已是最新版本({version})"
},
"distribution": {
@@ -2467,7 +2488,10 @@
"commits": "提交"
},
"noFolderTitle": "尚無開啟的資料夾",
- "noFolderHint": "開啟一個資料夾後可在此查看"
+ "noFolderHint": "開啟一個資料夾後可在此查看",
+ "openFullPage": "在完整頁面中開啟",
+ "back": "返回",
+ "noAutomations": "此專案還沒有自動化"
},
"windowControls": {
"minimizeWindow": "最小化視窗",
@@ -3366,6 +3390,7 @@
},
"messageInput": {
"askAnything": "請開始輸入...",
+ "promptSuggestion": "{suggestion}(按 Tab 填入)",
"removeAttachmentAria": "移除 {name}",
"attachFiles": "附加檔案",
"addActions": "新增",
@@ -3395,6 +3420,10 @@
"searchModelAria": "搜尋模型",
"modelListLabel": "模型",
"recommendedBadge": "推薦",
+ "recommendedValue": "推薦:{value}",
+ "searchOptions": "搜尋選項...",
+ "searchOptionsAria": "搜尋選項",
+ "noOptions": "找不到選項",
"noModels": "找不到模型",
"cancel": "取消",
"send": "傳送",
@@ -4007,13 +4036,16 @@
},
"messageNav": {
"title": "訊息導覽",
- "collapse": "收合訊息導覽",
"loadingEarlier": "正在載入更早的訊息…",
"loadEarlier": "載入更早的訊息",
- "collapsedSummary": "訊息 {count}",
"fileCount": "{count} 個檔案",
- "remove": "移除",
- "noDiffDataAvailable": "找不到 {filePath} 的差異資料"
+ "subAgentCount": "{count} 個子智能體",
+ "showDiff": "展開 {filePath} 的變更",
+ "hideDiff": "收合 {filePath} 的變更",
+ "openFile": "開啟 {filePath}",
+ "collapse": "收合",
+ "currentMessage": "目前訊息",
+ "scrollToCurrent": "捲動到目前訊息(#{ordinal})"
},
"replyArtifacts": {
"title": "變更檔案",
@@ -4071,6 +4103,9 @@
"resumeDelegation": "恢復任務 {task}",
"resumeDelegationNoId": "恢復委派任務",
"promptLabel": "指令",
+ "ackRecorded": "已記錄到待辦任務",
+ "ackNotRecorded": "未記錄到待辦任務",
+ "ackNotRecordedWithReason": "未記錄到待辦任務:{reason}",
"verdict": {
"success": "成功",
"needs_review": "待複核",
@@ -4188,6 +4223,18 @@
"stopDeclined": "無法停止該任務,它可能已經結束。",
"stopFailed": "停止任務失敗:{error}"
},
+ "remoteControl": {
+ "title": "遠端控制已開啟",
+ "open": "在瀏覽器中開啟",
+ "copy": "複製連結",
+ "copied": "已複製",
+ "qr": "QR 碼",
+ "qrLabel": "本會話遠端控制連結的 QR 碼",
+ "qrHint": "用手機掃描,在 Claude App 或 claude.ai/code 上繼續本會話。",
+ "noUrl": "Claude Code 沒有傳回本會話的連結",
+ "turnOff": "關閉",
+ "turnOffBusy": "Claude 完成目前工作後可用"
+ },
"proposedPlan": {
"title": "計劃提案",
"planning": "規劃中…"
@@ -7365,13 +7412,6 @@
}
},
"FloatingBall": {
- "label": "懸浮球",
- "panelTitle": "快捷操作",
- "settingsTitle": "懸浮球",
- "close": "關閉",
- "resetPosition": "重設位置",
- "cheatSheetTitle": "手勢",
- "hint": "拖動懸浮球可移動位置。快速滑動觸發手勢,長按打開此面板。",
"actions": {
"newConversation": "新增對話",
"toggleSidebar": "切換側欄",
@@ -7437,7 +7477,6 @@
"upLeftThenRight": "↖ 然後 →",
"upRightThenLeft": "↗ 然後 ←"
},
- "favoriteAgentsEmpty": "暫無可用代理人",
"toasts": {
"renameNeedsSavedSession": "重新命名只對已儲存的會話生效——先發一則訊息。",
"sessionFolderNeedsWorkspace": "請先開啟一個工作區資料夾。",
@@ -7450,6 +7489,14 @@
"noModesAvailable": "該智慧代理沒有可用模式。",
"noSwitchTarget": "沒有可切換的模式(未找到 Plan 或完整存取模式)。"
},
+ "label": "懸浮球",
+ "panelTitle": "快捷操作",
+ "settingsTitle": "懸浮球",
+ "close": "關閉",
+ "resetPosition": "重設位置",
+ "cheatSheetTitle": "手勢",
+ "hint": "拖動懸浮球可移動位置。快速滑動觸發手勢,長按打開此面板。",
+ "favoriteAgentsEmpty": "暫無可用代理人",
"recentSessionDepth": "最近會話切換深度",
"bindingCleared": "未綁定"
}
diff --git a/src/lib/default-mode-prefs.ts b/src/lib/default-mode-prefs.ts
new file mode 100644
index 0000000000..b78fc61d23
--- /dev/null
+++ b/src/lib/default-mode-prefs.ts
@@ -0,0 +1,32 @@
+/**
+ * Classification helper shared by the floating ball's "Plan ⇄ full access"
+ * toggle: identify the full-access mode among an agent's advertised mode ids.
+ * Each CLI calls full access something else (zcode `yolo`, codex
+ * `danger-full-access`, claude `bypassPermissions`), so the match runs a fixed
+ * weight order of well-known substrings — no blind id guessing, the backend
+ * would silently drop a wrong preferred id.
+ */
+
+/** Substrings that identify a full-access mode, in match priority order. */
+export const FULL_ACCESS_WEIGHTS = [
+ "danger",
+ "bypass",
+ "yolo",
+ "full",
+ "access",
+] as const
+
+/**
+ * Match a full-access mode among the advertised ids. Weight order decides
+ * between multiple hits (an agent offering both `yolo` and
+ * `danger-full-access` gets the `danger` one); ties resolve by list order so
+ * the result is stable across restarts.
+ */
+export function matchFullAccessMode(modeIds: readonly string[]): string | null {
+ for (const weight of FULL_ACCESS_WEIGHTS) {
+ for (const id of modeIds) {
+ if (id.toLowerCase().includes(weight)) return id
+ }
+ }
+ return null
+}
From fa04efc250d6e9c9d5e6860d2052fdeff2d35889 Mon Sep 17 00:00:00 2001
From: fengx
Date: Mon, 19 Oct 2026 02:55:50 +0800
Subject: [PATCH 10/18] chore(fork): point updater at fork releases + fork
signing pubkey + auto-sync release workflow
- update URLs (manifest + tarball base) -> unixcs/codeg releases/latest
- embedded minisign pubkey -> fork signing key
- fork-release.yml: on upstream release, merge upstream tag, build linux-x64
server bundle (server + mcp + computer-helper + web), sign with fork key,
publish tarball/.sig/.sha256/latest.json to fork release
---
.github/scripts/upstream-release-trigger.sh | 12 ++
.github/workflows/fork-release.yml | 176 ++++++++++++++++++++
src-tauri/src/update/verify.rs | 2 +-
src-tauri/src/update/version.rs | 4 +-
src-tauri/tauri.conf.json | 2 +-
5 files changed, 192 insertions(+), 4 deletions(-)
create mode 100755 .github/scripts/upstream-release-trigger.sh
create mode 100644 .github/workflows/fork-release.yml
diff --git a/.github/scripts/upstream-release-trigger.sh b/.github/scripts/upstream-release-trigger.sh
new file mode 100755
index 0000000000..9f99b32d72
--- /dev/null
+++ b/.github/scripts/upstream-release-trigger.sh
@@ -0,0 +1,12 @@
+#!/usr/bin/env bash
+# 上游 codeg 发版触发器:personal token 调 repository_dispatch 唤醒 fork 的 fork-release workflow。
+# cron 建议:每 6 小时一次(上游更新再频繁也足够及时)。
+# 用法:CODEG_DISPATCH_TOKEN=ghp_xxx ./upstream-release-trigger.sh
+set -euo pipefail
+: "${CODEG_DISPATCH_TOKEN:?need a personal access token with repo scope}"
+curl -sS -X POST \
+ -H "Accept: application/vnd.github+json" \
+ -H "Authorization: Bearer $CODEG_DISPATCH_TOKEN" \
+ https://api.github.com/repos/unixcs/codeg/dispatches \
+ -d '{"event_type":"upstream-release","client_payload":{}}'
+echo "dispatch sent"
diff --git a/.github/workflows/fork-release.yml b/.github/workflows/fork-release.yml
new file mode 100644
index 0000000000..caf4fc9f11
--- /dev/null
+++ b/.github/workflows/fork-release.yml
@@ -0,0 +1,176 @@
+name: Fork release (auto-sync upstream)
+
+# 当上游 spacering-net/codeg 发布新 release 时自动:
+# 1. 把上游 tag 合并进本分支(deploy/fork-updater,含 fork 更新源补丁)
+# 2. 构建 linux-x64 服务端包(codeg-server + sidecars + web 静态资产)
+# 3. 用 fork 自己的 minisign 密钥签名(--app-version 绑定版本)
+# 4. 生成 latest.json 并连同 tarball/.sig/.sha256 发到 fork 的同名 release
+# tx/dell 上的 codeg 检查的是 fork 的 releases/latest,于是走它自带的一键更新。
+#
+# 冲突时合并会失败 → job 标红 + 开 issue 通知,需人工解决。
+
+on:
+ # 上游发版触发(repository_dispatch 由 personal token 定时调用,
+ # 因为 fork 不能直接监听上游的 release 事件)
+ repository_dispatch:
+ types: [upstream-release]
+ workflow_dispatch:
+
+permissions:
+ contents: write
+ issues: write
+
+concurrency:
+ group: fork-release
+ cancel-in-progress: false
+
+jobs:
+ sync-and-release:
+ runs-on: ubuntu-22.04
+ timeout-minutes: 90
+ steps:
+ - name: Check out deploy branch
+ uses: actions/checkout@v4
+ with:
+ ref: deploy/fork-updater
+ fetch-depth: 0
+ token: ${{ secrets.FORK_SYNC_TOKEN }}
+
+ - name: Resolve upstream latest release
+ id: upstream
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ set -euo pipefail
+ info=$(gh api repos/spacering-net/codeg/releases/latest --jq '{tag: .tag_name, ver: (.tag_name | ltrimstr("v")), notes: .body}')
+ echo "tag=$(echo "$info" | jq -r .tag)" >> "$GITHUB_OUTPUT"
+ echo "ver=$(echo "$info" | jq -r .ver)" >> "$GITHUB_OUTPUT"
+ echo "$info" | jq -r .notes > /tmp/upstream-notes.md
+ echo "Upstream: $(echo "$info" | jq -r .tag)"
+
+ - name: Skip if fork already has this release
+ id: skip
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ set -euo pipefail
+ if gh release view "${{ steps.upstream.outputs.tag }}" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
+ echo "already=true" >> "$GITHUB_OUTPUT"
+ echo "Release ${{ steps.upstream.outputs.tag }} already exists on fork — nothing to do."
+ else
+ echo "already=false" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: Merge upstream tag into deploy branch
+ if: steps.skip.outputs.already == 'false'
+ id: merge
+ run: |
+ set -euo pipefail
+ git config user.name "fork-sync-bot"
+ git config user.email "bot@users.noreply.github.com"
+ git remote add upstream https://github.com/spacering-net/codeg.git
+ git fetch upstream "${{ steps.upstream.outputs.tag }}"
+ if git merge --no-edit FETCH_HEAD; then
+ git push origin deploy/fork-updater
+ echo "merged=true" >> "$GITHUB_OUTPUT"
+ else
+ git merge --abort || true
+ echo "merged=false" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: Open issue on merge conflict
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'false'
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ run: |
+ gh issue create --repo "$GITHUB_REPOSITORY" \
+ --title "上游 ${{ steps.upstream.outputs.tag }} 合并冲突,需人工介入" \
+ --body "spacering-net/codeg 发布了 ${{ steps.upstream.outputs.tag }},合并进 deploy/fork-updater 时有冲突。请本地执行:git fetch upstream && git merge ${{ steps.upstream.outputs.tag }},解决冲突(保留悬浮球与 fork 补丁)后 push。"
+
+ - name: Install pnpm deps
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ uses: pnpm/action-setup@v4
+ with:
+ version: 9
+
+ - name: Set up Node
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ uses: actions/setup-node@v4
+ with:
+ node-version: 22
+ cache: pnpm
+
+ - name: Install dependencies
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ run: pnpm install --frozen-lockfile
+
+ - name: Build frontend
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ run: pnpm build
+
+ - name: Set up Rust
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ uses: dtolnay/rust-toolchain@stable
+
+ - name: Cache cargo
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ uses: swatinem/rust-cache@v2
+ with:
+ workspaces: src-tauri
+
+ - name: Build server + sidecars
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ run: |
+ set -euo pipefail
+ cd src-tauri
+ cargo build --release --bin codeg-server --no-default-features --features server-bin
+ cargo build --release --no-default-features --features mcp-bin,computer-helper --bins
+ cd ..
+ mkdir -p dist/codeg-server-linux-x64
+ cp src-tauri/target/release/codeg-server dist/codeg-server-linux-x64/
+ cp src-tauri/target/release/codeg-mcp dist/codeg-server-linux-x64/
+ cp src-tauri/target/release/codeg-computer-helper dist/codeg-server-linux-x64/
+ chmod +x dist/codeg-server-linux-x64/*
+ cp -r out dist/codeg-server-linux-x64/web
+ cd dist && tar czf codeg-server-linux-x64.tar.gz codeg-server-linux-x64
+
+ - name: Sign bundle with fork key
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ env:
+ TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}
+ TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ""
+ run: |
+ set -euo pipefail
+ pnpm tauri signer sign --app-version "${{ steps.upstream.outputs.ver }}" "dist/codeg-server-linux-x64.tar.gz"
+ test -f dist/codeg-server-linux-x64.tar.gz.sig
+ ( cd dist && sha256sum codeg-server-linux-x64.tar.gz > codeg-server-linux-x64.tar.gz.sha256 )
+
+ - name: Build latest.json
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ env:
+ VER: ${{ steps.upstream.outputs.ver }}
+ run: |
+ set -euo pipefail
+ SIG=$(base64 -w0 dist/codeg-server-linux-x64.tar.gz.sig)
+ URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${{ steps.upstream.outputs.tag }}/codeg-server-linux-x64.tar.gz"
+ jq -n --arg v "$VER" --arg s "$SIG" --arg u "$URL" --rawfile n /tmp/upstream-notes.md \
+ '{version: $v, notes: $n, pub_date: (now | todateiso8601),
+ platforms: {"linux-x86_64": {signature: $s, url: $u}}}' > dist/latest.json
+ cat dist/latest.json | jq -r '.version, .platforms["linux-x86_64"].url'
+
+ - name: Create fork release and upload
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ env:
+ GH_TOKEN: ${{ secrets.FORK_SYNC_TOKEN }}
+ run: |
+ set -euo pipefail
+ gh release create "${{ steps.upstream.outputs.tag }}" \
+ --repo "$GITHUB_REPOSITORY" \
+ --title "codeg ${{ steps.upstream.outputs.ver }} + floating-ball (fork)" \
+ --notes "基于上游 ${{ steps.upstream.outputs.tag }},含悬浮球功能与 fork 更新源补丁。
+
+ $(cat /tmp/upstream-notes.md)" \
+ dist/codeg-server-linux-x64.tar.gz \
+ dist/codeg-server-linux-x64.tar.gz.sig \
+ dist/codeg-server-linux-x64.tar.gz.sha256 \
+ dist/latest.json
diff --git a/src-tauri/src/update/verify.rs b/src-tauri/src/update/verify.rs
index 6401eff484..3748c9d17e 100644
--- a/src-tauri/src/update/verify.rs
+++ b/src-tauri/src/update/verify.rs
@@ -23,7 +23,7 @@ use crate::update::version::trim_v_prefix;
/// Tauri-format minisign public key — copied verbatim from
/// `tauri.conf.json` `plugins.updater.pubkey`. Base64 of the two-line
/// `minisign.pub` file (`untrusted comment:` + `RW…` key line).
-const TAURI_PUBKEY_B64: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDQ4OEM3NkMyMTVENjdBODgKUldTSWV0WVZ3bmFNU0NnSzhpdFg2bXFmMHFidWd1eWpuZ2Y2WmU5QmVXdWVrU0ZpOCt2dnd6WW4K";
+const TAURI_PUBKEY_B64: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDc1OEQ2MDVCMUU3Qjk4MjkKUldRcG1Ic2VXMkNOZFRWMTNRSHpRcGgvWjFBWmVNZVJZWi9MbGpZS1RpSEFBeGJyYTZ0cThUOHkK";
/// Decode an outer base64 wrapper into the inner minisign text file.
fn unwrap_base64(b64: &str) -> Result {
diff --git a/src-tauri/src/update/version.rs b/src-tauri/src/update/version.rs
index 71715ae403..4e697e1717 100644
--- a/src-tauri/src/update/version.rs
+++ b/src-tauri/src/update/version.rs
@@ -16,12 +16,12 @@ use crate::app_error::AppCommandError;
/// Update manifest URL — mirrors the `endpoints` entry in `tauri.conf.json`
/// so desktop and server modes consult the same source of truth.
pub const UPDATE_MANIFEST_URL: &str =
- "https://github.com/spacering-net/codeg/releases/latest/download/latest.json";
+ "https://github.com/unixcs/codeg/releases/latest/download/latest.json";
/// Deterministic base for "latest" release assets (server tarballs + their
/// `.sig` detached signatures). Same channel as the manifest.
pub const RELEASE_DOWNLOAD_BASE: &str =
- "https://github.com/spacering-net/codeg/releases/latest/download";
+ "https://github.com/unixcs/codeg/releases/latest/download";
/// Short-timeout client for the small manifest fetch. Proxy env vars are
/// sampled at build time, so `init_proxy_from_db` must run before the first
diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json
index 436fb91604..5dbd24db60 100644
--- a/src-tauri/tauri.conf.json
+++ b/src-tauri/tauri.conf.json
@@ -53,7 +53,7 @@
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDQ4OEM3NkMyMTVENjdBODgKUldTSWV0WVZ3bmFNU0NnSzhpdFg2bXFmMHFidWd1eWpuZ2Y2WmU5QmVXdWVrU0ZpOCt2dnd6WW4K",
"endpoints": [
- "https://github.com/spacering-net/codeg/releases/latest/download/latest.json"
+ "https://github.com/unixcs/codeg/releases/latest/download/latest.json"
],
"requireSignedVersion": true,
"windows": {
From c63e8ea6710f054b2244f00a420c90c15156426d Mon Sep 17 00:00:00 2001
From: fengx
Date: Tue, 20 Oct 2026 02:06:11 +0800
Subject: [PATCH 11/18] ci: trigger workflow registration on fork
From 47b8348d89fe6b18535da76e61ac98cf5b5b15a1 Mon Sep 17 00:00:00 2001
From: fengx
Date: Tue, 20 Oct 2026 02:15:46 +0800
Subject: [PATCH 12/18] ci: fall back to GITHUB_TOKEN when FORK_SYNC_TOKEN
absent
---
.github/workflows/fork-release.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/fork-release.yml b/.github/workflows/fork-release.yml
index caf4fc9f11..d65402c304 100644
--- a/.github/workflows/fork-release.yml
+++ b/.github/workflows/fork-release.yml
@@ -34,7 +34,7 @@ jobs:
with:
ref: deploy/fork-updater
fetch-depth: 0
- token: ${{ secrets.FORK_SYNC_TOKEN }}
+ token: ${{ secrets.GITHUB_TOKEN || secrets.FORK_SYNC_TOKEN }}
- name: Resolve upstream latest release
id: upstream
From 8d1e9b262a8c513112c4f237bffd6e0cb7c559a4 Mon Sep 17 00:00:00 2001
From: fengx
Date: Tue, 20 Oct 2026 02:19:15 +0800
Subject: [PATCH 13/18] ci: push merge with FORK_SYNC_TOKEN (GITHUB_TOKEN lacks
workflows scope)
---
.github/workflows/fork-release.yml | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/.github/workflows/fork-release.yml b/.github/workflows/fork-release.yml
index d65402c304..0c6da17410 100644
--- a/.github/workflows/fork-release.yml
+++ b/.github/workflows/fork-release.yml
@@ -64,6 +64,8 @@ jobs:
- name: Merge upstream tag into deploy branch
if: steps.skip.outputs.already == 'false'
id: merge
+ env:
+ FORK_TOKEN: ${{ secrets.FORK_SYNC_TOKEN }}
run: |
set -euo pipefail
git config user.name "fork-sync-bot"
@@ -71,7 +73,10 @@ jobs:
git remote add upstream https://github.com/spacering-net/codeg.git
git fetch upstream "${{ steps.upstream.outputs.tag }}"
if git merge --no-edit FETCH_HEAD; then
- git push origin deploy/fork-updater
+ # 合并可能动了 .github/workflows(上游 release.yml 有变化时),
+ # GITHUB_TOKEN 无 workflows 权限推不了 → 只推非 workflow 文件也行:
+ # 简化处理:改用 FORK_SYNC_TOKEN 推(见 checkout 同款 token)。
+ git push "https://x-access-token:${FORK_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" deploy/fork-updater
echo "merged=true" >> "$GITHUB_OUTPUT"
else
git merge --abort || true
From f8c85c911359e7fdd2c6ba21bdb66011035ac9fb Mon Sep 17 00:00:00 2001
From: fengx
Date: Tue, 20 Oct 2026 02:27:49 +0800
Subject: [PATCH 14/18] ci: keep upstream workflow changes out of deploy branch
push (GITHUB_TOKEN can't touch workflows)
---
.github/workflows/fork-release.yml | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/.github/workflows/fork-release.yml b/.github/workflows/fork-release.yml
index 0c6da17410..99c3073849 100644
--- a/.github/workflows/fork-release.yml
+++ b/.github/workflows/fork-release.yml
@@ -73,10 +73,16 @@ jobs:
git remote add upstream https://github.com/spacering-net/codeg.git
git fetch upstream "${{ steps.upstream.outputs.tag }}"
if git merge --no-edit FETCH_HEAD; then
- # 合并可能动了 .github/workflows(上游 release.yml 有变化时),
- # GITHUB_TOKEN 无 workflows 权限推不了 → 只推非 workflow 文件也行:
- # 简化处理:改用 FORK_SYNC_TOKEN 推(见 checkout 同款 token)。
- git push "https://x-access-token:${FORK_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" deploy/fork-updater
+ # 合并会带来 .github/workflows 的上游改动,GITHUB_TOKEN 没有
+ # workflows 权限推不动整个分支。所以只把**源码/构建相关**的合并
+ # 结果同步回远端:用 treeless 方式把合并提交拆成"代码树"推送——
+ # 简化做法:推送前把 workflow 文件 checkout 回 deploy 分支原来的
+ # 版本(上游对 release.yml 的改动对 fork 构建无用,fork 不跑
+ # 上游 release.yml,跑的是 fork-release.yml),这样 push 永远
+ # 不碰 workflow 文件,GITHUB_TOKEN 就够用。
+ git checkout HEAD -- .github/workflows/
+ git commit --amend --no-edit --quiet
+ git push "https://x-access-token:${FORK_TOKEN:-$(git config --get-urlmatch http.extraheader 2>/dev/null || true)}@github.com/${GITHUB_REPOSITORY}.git" deploy/fork-updater 2>/dev/null || git push origin deploy/fork-updater
echo "merged=true" >> "$GITHUB_OUTPUT"
else
git merge --abort || true
From bac24b02df847b28554d2803f4b3a60cb7985053 Mon Sep 17 00:00:00 2001
From: fengx
Date: Tue, 20 Oct 2026 02:39:17 +0800
Subject: [PATCH 15/18] ci: merge upstream locally without pushing back;
package all 4 binaries like official release
---
.github/workflows/fork-release.yml | 93 ++++++++++++++++--------------
1 file changed, 50 insertions(+), 43 deletions(-)
diff --git a/.github/workflows/fork-release.yml b/.github/workflows/fork-release.yml
index 99c3073849..8b6db72251 100644
--- a/.github/workflows/fork-release.yml
+++ b/.github/workflows/fork-release.yml
@@ -1,17 +1,19 @@
name: Fork release (auto-sync upstream)
# 当上游 spacering-net/codeg 发布新 release 时自动:
-# 1. 把上游 tag 合并进本分支(deploy/fork-updater,含 fork 更新源补丁)
-# 2. 构建 linux-x64 服务端包(codeg-server + sidecars + web 静态资产)
+# 1. 在 CI 里把上游 tag 合并进 deploy/fork-updater(含 fork 更新源补丁+悬浮球)
+# 2. 构建 linux-x64 服务端包(codeg-server + codeg-mcp + codeg-cli
+# + codeg-computer-helper + web 静态资产),与官方 tarball 同构
# 3. 用 fork 自己的 minisign 密钥签名(--app-version 绑定版本)
# 4. 生成 latest.json 并连同 tarball/.sig/.sha256 发到 fork 的同名 release
-# tx/dell 上的 codeg 检查的是 fork 的 releases/latest,于是走它自带的一键更新。
+# tx/dell 上的 codeg 检查的是 fork 的 releases/latest,走它自带的一键更新。
#
-# 冲突时合并会失败 → job 标红 + 开 issue 通知,需人工解决。
+# 注意:合并结果**不回推** deploy 分支——GITHUB_TOKEN 无 workflows 权限,
+# 合并若带入 .github/workflows 改动,push 必被拒。deploy 分支的源码由
+# 人工维护(上游合并有冲突时本地解决后 push),CI 每次都从上游 tag 现合。
+# 冲突时合并失败 → job 标红 + 开 issue 通知,需人工解决。
on:
- # 上游发版触发(repository_dispatch 由 personal token 定时调用,
- # 因为 fork 不能直接监听上游的 release 事件)
repository_dispatch:
types: [upstream-release]
workflow_dispatch:
@@ -24,6 +26,9 @@ concurrency:
group: fork-release
cancel-in-progress: false
+env:
+ ARTIFACT: codeg-server-linux-x64
+
jobs:
sync-and-release:
runs-on: ubuntu-22.04
@@ -34,7 +39,7 @@ jobs:
with:
ref: deploy/fork-updater
fetch-depth: 0
- token: ${{ secrets.GITHUB_TOKEN || secrets.FORK_SYNC_TOKEN }}
+ token: ${{ secrets.FORK_SYNC_TOKEN || secrets.GITHUB_TOKEN }}
- name: Resolve upstream latest release
id: upstream
@@ -61,11 +66,9 @@ jobs:
echo "already=false" >> "$GITHUB_OUTPUT"
fi
- - name: Merge upstream tag into deploy branch
+ - name: Merge upstream tag (local only, not pushed back)
if: steps.skip.outputs.already == 'false'
id: merge
- env:
- FORK_TOKEN: ${{ secrets.FORK_SYNC_TOKEN }}
run: |
set -euo pipefail
git config user.name "fork-sync-bot"
@@ -73,17 +76,8 @@ jobs:
git remote add upstream https://github.com/spacering-net/codeg.git
git fetch upstream "${{ steps.upstream.outputs.tag }}"
if git merge --no-edit FETCH_HEAD; then
- # 合并会带来 .github/workflows 的上游改动,GITHUB_TOKEN 没有
- # workflows 权限推不动整个分支。所以只把**源码/构建相关**的合并
- # 结果同步回远端:用 treeless 方式把合并提交拆成"代码树"推送——
- # 简化做法:推送前把 workflow 文件 checkout 回 deploy 分支原来的
- # 版本(上游对 release.yml 的改动对 fork 构建无用,fork 不跑
- # 上游 release.yml,跑的是 fork-release.yml),这样 push 永远
- # 不碰 workflow 文件,GITHUB_TOKEN 就够用。
- git checkout HEAD -- .github/workflows/
- git commit --amend --no-edit --quiet
- git push "https://x-access-token:${FORK_TOKEN:-$(git config --get-urlmatch http.extraheader 2>/dev/null || true)}@github.com/${GITHUB_REPOSITORY}.git" deploy/fork-updater 2>/dev/null || git push origin deploy/fork-updater
echo "merged=true" >> "$GITHUB_OUTPUT"
+ git log --oneline -1
else
git merge --abort || true
echo "merged=false" >> "$GITHUB_OUTPUT"
@@ -96,19 +90,19 @@ jobs:
run: |
gh issue create --repo "$GITHUB_REPOSITORY" \
--title "上游 ${{ steps.upstream.outputs.tag }} 合并冲突,需人工介入" \
- --body "spacering-net/codeg 发布了 ${{ steps.upstream.outputs.tag }},合并进 deploy/fork-updater 时有冲突。请本地执行:git fetch upstream && git merge ${{ steps.upstream.outputs.tag }},解决冲突(保留悬浮球与 fork 补丁)后 push。"
+ --body "spacering-net/codeg 发布了 ${{ steps.upstream.outputs.tag }},CI 合并进 deploy/fork-updater 时有冲突,本次未出包。请在本地:git fetch upstream && git merge ${{ steps.upstream.outputs.tag }},解决冲突(保留悬浮球与 fork 更新源补丁)后 push 到 deploy 分支,然后手动重跑 workflow。"
- name: Install pnpm deps
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
uses: pnpm/action-setup@v4
with:
- version: 9
+ version: 11
- name: Set up Node
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
uses: actions/setup-node@v4
with:
- node-version: 22
+ node-version: 24
cache: pnpm
- name: Install dependencies
@@ -129,21 +123,34 @@ jobs:
with:
workspaces: src-tauri
- - name: Build server + sidecars
+ - name: Build server + companions (mirror official release.yml)
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
run: |
set -euo pipefail
cd src-tauri
cargo build --release --bin codeg-server --no-default-features --features server-bin
- cargo build --release --no-default-features --features mcp-bin,computer-helper --bins
+ cargo build --release --bin codeg-mcp --no-default-features --features mcp-bin
+ cargo build --release --bin codeg-computer-helper --no-default-features --features computer-helper
+ cargo build --release --bin codeg-cli --no-default-features --features cli-bin
cd ..
- mkdir -p dist/codeg-server-linux-x64
- cp src-tauri/target/release/codeg-server dist/codeg-server-linux-x64/
- cp src-tauri/target/release/codeg-mcp dist/codeg-server-linux-x64/
- cp src-tauri/target/release/codeg-computer-helper dist/codeg-server-linux-x64/
- chmod +x dist/codeg-server-linux-x64/*
- cp -r out dist/codeg-server-linux-x64/web
- cd dist && tar czf codeg-server-linux-x64.tar.gz codeg-server-linux-x64
+ mkdir -p dist/${ARTIFACT}
+ cp src-tauri/target/release/codeg-server dist/${ARTIFACT}/
+ cp src-tauri/target/release/codeg-mcp dist/${ARTIFACT}/
+ cp src-tauri/target/release/codeg-computer-helper dist/${ARTIFACT}/
+ cp src-tauri/target/release/codeg-cli dist/${ARTIFACT}/
+ chmod +x dist/${ARTIFACT}/*
+ cp -r out dist/${ARTIFACT}/web
+ cd dist && tar czf ${ARTIFACT}.tar.gz ${ARTIFACT}
+
+ - name: Smoke test packaged artifact
+ if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
+ run: |
+ set -euo pipefail
+ test -x "dist/${ARTIFACT}/codeg-server"
+ test -x "dist/${ARTIFACT}/codeg-mcp"
+ test -x "dist/${ARTIFACT}/codeg-computer-helper"
+ test -x "dist/${ARTIFACT}/codeg-cli"
+ test -f "dist/${ARTIFACT}/web/index.html"
- name: Sign bundle with fork key
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
@@ -152,9 +159,9 @@ jobs:
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ""
run: |
set -euo pipefail
- pnpm tauri signer sign --app-version "${{ steps.upstream.outputs.ver }}" "dist/codeg-server-linux-x64.tar.gz"
- test -f dist/codeg-server-linux-x64.tar.gz.sig
- ( cd dist && sha256sum codeg-server-linux-x64.tar.gz > codeg-server-linux-x64.tar.gz.sha256 )
+ pnpm tauri signer sign --app-version "${{ steps.upstream.outputs.ver }}" "dist/${ARTIFACT}.tar.gz"
+ test -f "dist/${ARTIFACT}.tar.gz.sig"
+ ( cd dist && sha256sum ${ARTIFACT}.tar.gz > ${ARTIFACT}.tar.gz.sha256 )
- name: Build latest.json
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
@@ -162,26 +169,26 @@ jobs:
VER: ${{ steps.upstream.outputs.ver }}
run: |
set -euo pipefail
- SIG=$(base64 -w0 dist/codeg-server-linux-x64.tar.gz.sig)
- URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${{ steps.upstream.outputs.tag }}/codeg-server-linux-x64.tar.gz"
+ SIG=$(base64 -w0 "dist/${ARTIFACT}.tar.gz.sig")
+ URL="https://github.com/${GITHUB_REPOSITORY}/releases/download/${{ steps.upstream.outputs.tag }}/${ARTIFACT}.tar.gz"
jq -n --arg v "$VER" --arg s "$SIG" --arg u "$URL" --rawfile n /tmp/upstream-notes.md \
'{version: $v, notes: $n, pub_date: (now | todateiso8601),
platforms: {"linux-x86_64": {signature: $s, url: $u}}}' > dist/latest.json
- cat dist/latest.json | jq -r '.version, .platforms["linux-x86_64"].url'
+ jq -r '.version, .platforms["linux-x86_64"].url' dist/latest.json
- name: Create fork release and upload
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
env:
- GH_TOKEN: ${{ secrets.FORK_SYNC_TOKEN }}
+ GH_TOKEN: ${{ secrets.FORK_SYNC_TOKEN || secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
gh release create "${{ steps.upstream.outputs.tag }}" \
--repo "$GITHUB_REPOSITORY" \
--title "codeg ${{ steps.upstream.outputs.ver }} + floating-ball (fork)" \
- --notes "基于上游 ${{ steps.upstream.outputs.tag }},含悬浮球功能与 fork 更新源补丁。
+ --notes "基于上游 ${{ steps.upstream.outputs.tag }},含悬浮球功能与 fork 更新源补丁。仅打包 linux-x64。
$(cat /tmp/upstream-notes.md)" \
- dist/codeg-server-linux-x64.tar.gz \
- dist/codeg-server-linux-x64.tar.gz.sig \
- dist/codeg-server-linux-x64.tar.gz.sha256 \
+ "dist/${ARTIFACT}.tar.gz" \
+ "dist/${ARTIFACT}.tar.gz.sig" \
+ "dist/${ARTIFACT}.tar.gz.sha256" \
dist/latest.json
From cd6ea09ea8832ea569d61f30b56a4ca2ec28c8e9 Mon Sep 17 00:00:00 2001
From: fengx
Date: Tue, 20 Oct 2026 02:45:16 +0800
Subject: [PATCH 16/18] ci: let pnpm/action-setup read packageManager version
---
.github/workflows/fork-release.yml | 2 --
1 file changed, 2 deletions(-)
diff --git a/.github/workflows/fork-release.yml b/.github/workflows/fork-release.yml
index 8b6db72251..541cefdfa5 100644
--- a/.github/workflows/fork-release.yml
+++ b/.github/workflows/fork-release.yml
@@ -95,8 +95,6 @@ jobs:
- name: Install pnpm deps
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
uses: pnpm/action-setup@v4
- with:
- version: 11
- name: Set up Node
if: steps.skip.outputs.already == 'false' && steps.merge.outputs.merged == 'true'
From da6e19049a9a747ac7ae756b2e70d6a6e99dd69f Mon Sep 17 00:00:00 2001
From: fengx
Date: Tue, 20 Oct 2026 04:48:28 +0800
Subject: [PATCH 17/18] feat(floating-ball): right-panel actions and double-tap
rebind (batch v86)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- New actions: toggleAuxPanel, openSessionDetails, openChanges, openGitLog —
the v0.38.0 right sidebar (aux panel) had no ball action at all; its toggle
now owns the unbound down stroke, and its two most-read tabs take the
downward diagonals.
- Double tap moves from the terminal to the right panel: the terminal keeps
its bound gestures, and the panel is the newer, higher-traffic surface on
the phone. Single tap already binds via the settings UI (panel by default).
- Labels for all 10 locales; binding dropdown and tap panel list the new
actions; tests updated for the new defaults.
---
src/components/layout/floating-ball.test.tsx | 3 ++-
src/components/layout/floating-ball.tsx | 4 +++
.../layout/workspace-chrome-controller.tsx | 21 +++++++++++++++
.../settings/appearance-settings.tsx | 4 +++
src/i18n/messages/ar.json | 4 +++
src/i18n/messages/de.json | 4 +++
src/i18n/messages/en.json | 4 +++
src/i18n/messages/es.json | 4 +++
src/i18n/messages/fr.json | 4 +++
src/i18n/messages/ja.json | 4 +++
src/i18n/messages/ko.json | 4 +++
src/i18n/messages/pt.json | 4 +++
src/i18n/messages/zh-CN.json | 4 +++
src/i18n/messages/zh-TW.json | 4 +++
src/lib/floating-ball-gestures.test.ts | 27 ++++++++++++-------
src/lib/floating-ball-gestures.ts | 19 ++++++++++---
16 files changed, 103 insertions(+), 15 deletions(-)
diff --git a/src/components/layout/floating-ball.test.tsx b/src/components/layout/floating-ball.test.tsx
index 81ce6c7ce1..6acbc86643 100644
--- a/src/components/layout/floating-ball.test.tsx
+++ b/src/components/layout/floating-ball.test.tsx
@@ -149,7 +149,8 @@ describe("FloatingBall", () => {
vi.advanceTimersByTime(100)
})
tap()
- expect(onAction).toHaveBeenCalledWith("toggleTerminal")
+ // Batch v86: the double tap moved from the terminal to the right panel.
+ expect(onAction).toHaveBeenCalledWith("toggleAuxPanel")
// The pending single tap must not fire as well.
act(() => {
vi.advanceTimersByTime(500)
diff --git a/src/components/layout/floating-ball.tsx b/src/components/layout/floating-ball.tsx
index 9e55480260..e62ef6d86b 100644
--- a/src/components/layout/floating-ball.tsx
+++ b/src/components/layout/floating-ball.tsx
@@ -44,6 +44,7 @@ const ICON_CLASS: Record = {
const PANEL_ACTIONS: readonly Exclude[] = [
"newConversation",
"toggleSidebar",
+ "toggleAuxPanel",
"toggleSearch",
"toggleTerminal",
"nextTab",
@@ -56,6 +57,9 @@ const PANEL_ACTIONS: readonly Exclude[] = [
"openCanvas",
"openAgents",
"openSystemAdmin",
+ "openSessionDetails",
+ "openChanges",
+ "openGitLog",
"renameConversation",
"openSessionFolder",
"cycleAgent",
diff --git a/src/components/layout/workspace-chrome-controller.tsx b/src/components/layout/workspace-chrome-controller.tsx
index e6db93539a..e962696b93 100644
--- a/src/components/layout/workspace-chrome-controller.tsx
+++ b/src/components/layout/workspace-chrome-controller.tsx
@@ -509,6 +509,9 @@ export function WorkspaceChromeController() {
case "toggleSidebar":
toggle()
return
+ case "toggleAuxPanel":
+ toggleAuxPanel()
+ return
case "toggleSearch":
setSearchOpen((prev) => !prev)
return
@@ -595,6 +598,23 @@ export function WorkspaceChromeController() {
}
auxPanel.openTab("file_tree")
return
+ case "openSessionDetails":
+ auxPanel.openTab("session_details")
+ return
+ case "openChanges":
+ if (!activeFolder) {
+ toast.info(tBall("toasts.sessionFolderNeedsWorkspace"))
+ return
+ }
+ auxPanel.openTab("changes")
+ return
+ case "openGitLog":
+ if (!activeFolder) {
+ toast.info(tBall("toasts.sessionFolderNeedsWorkspace"))
+ return
+ }
+ auxPanel.openTab("git_log")
+ return
case "cycleAgent":
case "cycleFavoriteAgent": {
const list =
@@ -740,6 +760,7 @@ export function WorkspaceChromeController() {
tBall,
tabs,
toggle,
+ toggleAuxPanel,
toggleTerminal,
zoomLevel,
]
diff --git a/src/components/settings/appearance-settings.tsx b/src/components/settings/appearance-settings.tsx
index 173175e272..1527a25a56 100644
--- a/src/components/settings/appearance-settings.tsx
+++ b/src/components/settings/appearance-settings.tsx
@@ -79,6 +79,7 @@ const BALL_BINDABLE_ACTIONS: readonly FloatingBallAction[] = [
"panel",
"newConversation",
"toggleSidebar",
+ "toggleAuxPanel",
"toggleSearch",
"toggleTerminal",
"nextTab",
@@ -91,6 +92,9 @@ const BALL_BINDABLE_ACTIONS: readonly FloatingBallAction[] = [
"openCanvas",
"openAgents",
"openSystemAdmin",
+ "openSessionDetails",
+ "openChanges",
+ "openGitLog",
"renameConversation",
"openSessionFolder",
"cycleAgent",
diff --git a/src/i18n/messages/ar.json b/src/i18n/messages/ar.json
index c3c56f5e4d..c9ec45f135 100644
--- a/src/i18n/messages/ar.json
+++ b/src/i18n/messages/ar.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "محادثة جديدة",
"toggleSidebar": "تبديل الشريط الجانبي",
+ "toggleAuxPanel": "تبديل اللوحة اليمنى",
"toggleSearch": "بحث",
"toggleTerminal": "تبديل الطرفية",
"nextTab": "التبويب التالي",
@@ -7453,6 +7454,9 @@
"openCanvas": "اللوحة",
"openAgents": "الوكلاء",
"openSystemAdmin": "إدارة النظام",
+ "openSessionDetails": "تفاصيل الجلسة",
+ "openChanges": "تغييرات Git",
+ "openGitLog": "الالتزامات",
"renameConversation": "إعادة تسمية المحادثة",
"openSessionFolder": "ملفات الجلسة",
"cycleAgent": "الوكيل التالي",
diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json
index 1231631568..8140cf4096 100644
--- a/src/i18n/messages/de.json
+++ b/src/i18n/messages/de.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "Neue Unterhaltung",
"toggleSidebar": "Seitenleiste umschalten",
+ "toggleAuxPanel": "Rechtes Panel umschalten",
"toggleSearch": "Suchen",
"toggleTerminal": "Terminal umschalten",
"nextTab": "Nächster Tab",
@@ -7453,6 +7454,9 @@
"openCanvas": "Canvas",
"openAgents": "Agenten",
"openSystemAdmin": "Systemverwaltung",
+ "openSessionDetails": "Sitzungsdetails",
+ "openChanges": "Git-Änderungen",
+ "openGitLog": "Commits",
"renameConversation": "Unterhaltung umbenennen",
"openSessionFolder": "Sitzungsdateien",
"cycleAgent": "Nächster Agent",
diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json
index bee3892eca..3c0fc61f03 100644
--- a/src/i18n/messages/en.json
+++ b/src/i18n/messages/en.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "New conversation",
"toggleSidebar": "Toggle sidebar",
+ "toggleAuxPanel": "Toggle right panel",
"toggleSearch": "Search",
"toggleTerminal": "Toggle terminal",
"nextTab": "Next tab",
@@ -7453,6 +7454,9 @@
"openCanvas": "Canvas",
"openAgents": "Agents",
"openSystemAdmin": "System admin",
+ "openSessionDetails": "Session details",
+ "openChanges": "Git changes",
+ "openGitLog": "Commits",
"renameConversation": "Rename conversation",
"openSessionFolder": "Session files",
"cycleAgent": "Next agent",
diff --git a/src/i18n/messages/es.json b/src/i18n/messages/es.json
index d274b91aca..8b94ac2a93 100644
--- a/src/i18n/messages/es.json
+++ b/src/i18n/messages/es.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "Nueva conversación",
"toggleSidebar": "Mostrar u ocultar la barra lateral",
+ "toggleAuxPanel": "Alternar panel derecho",
"toggleSearch": "Buscar",
"toggleTerminal": "Mostrar u ocultar la terminal",
"nextTab": "Pestaña siguiente",
@@ -7453,6 +7454,9 @@
"openCanvas": "Lienzo",
"openAgents": "Agentes",
"openSystemAdmin": "Administración",
+ "openSessionDetails": "Detalles de sesión",
+ "openChanges": "Cambios de Git",
+ "openGitLog": "Commits",
"renameConversation": "Renombrar conversación",
"openSessionFolder": "Archivos de sesión",
"cycleAgent": "Siguiente agente",
diff --git a/src/i18n/messages/fr.json b/src/i18n/messages/fr.json
index df0b63848c..2687755a2a 100644
--- a/src/i18n/messages/fr.json
+++ b/src/i18n/messages/fr.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "Nouvelle conversation",
"toggleSidebar": "Afficher ou masquer la barre latérale",
+ "toggleAuxPanel": "Basculer le panneau droit",
"toggleSearch": "Rechercher",
"toggleTerminal": "Afficher ou masquer le terminal",
"nextTab": "Onglet suivant",
@@ -7453,6 +7454,9 @@
"openCanvas": "Canvas",
"openAgents": "Agents",
"openSystemAdmin": "Administration",
+ "openSessionDetails": "Détails de session",
+ "openChanges": "Modifications Git",
+ "openGitLog": "Commits",
"renameConversation": "Renommer la conversation",
"openSessionFolder": "Fichiers de session",
"cycleAgent": "Agent suivant",
diff --git a/src/i18n/messages/ja.json b/src/i18n/messages/ja.json
index 0cb3c045cb..a45f9b6efd 100644
--- a/src/i18n/messages/ja.json
+++ b/src/i18n/messages/ja.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "新しい会話",
"toggleSidebar": "サイドバーの切り替え",
+ "toggleAuxPanel": "右パネルの切り替え",
"toggleSearch": "検索",
"toggleTerminal": "ターミナルの切り替え",
"nextTab": "次のタブ",
@@ -7453,6 +7454,9 @@
"openCanvas": "キャンバス",
"openAgents": "エージェント",
"openSystemAdmin": "システム管理",
+ "openSessionDetails": "セッション詳細",
+ "openChanges": "Git 変更",
+ "openGitLog": "コミット",
"renameConversation": "会話名を変更",
"openSessionFolder": "セッションファイル",
"cycleAgent": "次のエージェント",
diff --git a/src/i18n/messages/ko.json b/src/i18n/messages/ko.json
index f7c0777751..b9dc68dd92 100644
--- a/src/i18n/messages/ko.json
+++ b/src/i18n/messages/ko.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "새 대화",
"toggleSidebar": "사이드바 전환",
+ "toggleAuxPanel": "오른쪽 패널 전환",
"toggleSearch": "검색",
"toggleTerminal": "터미널 전환",
"nextTab": "다음 탭",
@@ -7453,6 +7454,9 @@
"openCanvas": "캔버스",
"openAgents": "에이전트",
"openSystemAdmin": "시스템 관리",
+ "openSessionDetails": "세션 세부정보",
+ "openChanges": "Git 변경 사항",
+ "openGitLog": "커밋",
"renameConversation": "대화 이름 바꾸기",
"openSessionFolder": "세션 파일",
"cycleAgent": "다음 에이전트",
diff --git a/src/i18n/messages/pt.json b/src/i18n/messages/pt.json
index 7eaad0aa49..741efc0626 100644
--- a/src/i18n/messages/pt.json
+++ b/src/i18n/messages/pt.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "Nova conversa",
"toggleSidebar": "Alternar barra lateral",
+ "toggleAuxPanel": "Alternar painel direito",
"toggleSearch": "Pesquisar",
"toggleTerminal": "Alternar terminal",
"nextTab": "Próxima aba",
@@ -7453,6 +7454,9 @@
"openCanvas": "Canvas",
"openAgents": "Agentes",
"openSystemAdmin": "Administração",
+ "openSessionDetails": "Detalhes da sessão",
+ "openChanges": "Alterações do Git",
+ "openGitLog": "Commits",
"renameConversation": "Renomear conversa",
"openSessionFolder": "Arquivos da sessão",
"cycleAgent": "Próximo agente",
diff --git a/src/i18n/messages/zh-CN.json b/src/i18n/messages/zh-CN.json
index e952b103bd..66e2dd7982 100644
--- a/src/i18n/messages/zh-CN.json
+++ b/src/i18n/messages/zh-CN.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "新建会话",
"toggleSidebar": "切换侧栏",
+ "toggleAuxPanel": "开关右侧面板",
"toggleSearch": "搜索",
"toggleTerminal": "切换终端",
"nextTab": "下一个标签",
@@ -7453,6 +7454,9 @@
"openCanvas": "无限画布",
"openAgents": "智能体",
"openSystemAdmin": "系统管理",
+ "openSessionDetails": "会话详情",
+ "openChanges": "Git 改动",
+ "openGitLog": "提交记录",
"renameConversation": "重命名会话",
"openSessionFolder": "会话文件",
"cycleAgent": "下一个智能体",
diff --git a/src/i18n/messages/zh-TW.json b/src/i18n/messages/zh-TW.json
index ed02652d68..cee2581641 100644
--- a/src/i18n/messages/zh-TW.json
+++ b/src/i18n/messages/zh-TW.json
@@ -7436,6 +7436,7 @@
"actions": {
"newConversation": "新增對話",
"toggleSidebar": "切換側欄",
+ "toggleAuxPanel": "開關右側面板",
"toggleSearch": "搜尋",
"toggleTerminal": "切換終端機",
"nextTab": "下一個分頁",
@@ -7453,6 +7454,9 @@
"openCanvas": "無限畫布",
"openAgents": "智慧代理人",
"openSystemAdmin": "系統管理",
+ "openSessionDetails": "會話詳情",
+ "openChanges": "Git 變更",
+ "openGitLog": "提交記錄",
"renameConversation": "重新命名會話",
"openSessionFolder": "會話檔案",
"cycleAgent": "下一個代理人",
diff --git a/src/lib/floating-ball-gestures.test.ts b/src/lib/floating-ball-gestures.test.ts
index 449326301a..80319b98d5 100644
--- a/src/lib/floating-ball-gestures.test.ts
+++ b/src/lib/floating-ball-gestures.test.ts
@@ -206,16 +206,11 @@ describe("default bindings", () => {
(gesture) => DEFAULT_FLOATING_BALL_BINDINGS[gesture] === null
)
// The long corner continuations are the only intentional gaps: a trail
- // passing through a two-stage binding would otherwise fire twice. The
- // straight down family stays recognisable but unbound by default — the
- // settings UI lets owners bind them.
- expect(unbound.sort()).toEqual([
- "down",
- "downLeft",
- "downRight",
- "upLeftThenRight",
- "upRightThenLeft",
- ])
+ // passing through a two-stage binding would otherwise fire twice. Batch
+ // v86 gave the straight down family the aux-panel bindings, so nothing
+ // recognisable is left idle except the corner continuations that must
+ // stay unreachable.
+ expect(unbound.sort()).toEqual(["upLeftThenRight", "upRightThenLeft"])
})
it("keeps the MindFS muscle memory for the headline gestures", () => {
@@ -226,4 +221,16 @@ describe("default bindings", () => {
"stopGenerating"
)
})
+
+ it("gives the right sidebar the down family and double tap", () => {
+ // Batch v86: the aux panel is the phone's newest high-traffic surface.
+ // Double tap moves off the terminal onto the panel toggle, and the two
+ // downward diagonals open its most-read tabs (↓ itself is the toggle;
+ // openGitLog stays unbound — three bindings on one family leave no
+ // unambiguous stroke for it, and the panel rail reaches it in one tap).
+ expect(DEFAULT_FLOATING_BALL_BINDINGS.down).toBe("toggleAuxPanel")
+ expect(DEFAULT_FLOATING_BALL_BINDINGS.doubleTap).toBe("toggleAuxPanel")
+ expect(DEFAULT_FLOATING_BALL_BINDINGS.downLeft).toBe("openChanges")
+ expect(DEFAULT_FLOATING_BALL_BINDINGS.downRight).toBe("openSessionDetails")
+ })
})
diff --git a/src/lib/floating-ball-gestures.ts b/src/lib/floating-ball-gestures.ts
index 85ea893dae..d24a73b337 100644
--- a/src/lib/floating-ball-gestures.ts
+++ b/src/lib/floating-ball-gestures.ts
@@ -54,6 +54,7 @@ export type FloatingBallAction =
| "panel"
| "newConversation"
| "toggleSidebar"
+ | "toggleAuxPanel"
| "toggleSearch"
| "toggleTerminal"
| "nextTab"
@@ -71,6 +72,9 @@ export type FloatingBallAction =
| "openCanvas"
| "openAgents"
| "openSystemAdmin"
+ | "openSessionDetails"
+ | "openChanges"
+ | "openGitLog"
| "renameConversation"
| "openSessionFolder"
| "cycleAgent"
@@ -128,21 +132,28 @@ export const FLOATING_BALL_GESTURES: readonly FloatingBallGesture[] = [
* `stopGenerating` stays on an inconspicuous compound on purpose — a gesture
* that aborts a running answer must not live next to the ones fingers find
* first.
+ *
+ * Batch v86 adds the right sidebar (aux panel) family: `toggleAuxPanel` takes
+ * the one unbound single stroke (↓), and the panel's three high-frequency tabs
+ * take the downward diagonals. Double tap moves from the terminal to the aux
+ * panel — the terminal keeps a bound gesture (↑), while before v0.38.0 the
+ * right panel had no ball action at all and is the newer, higher-traffic
+ * surface on the phone.
*/
export const DEFAULT_FLOATING_BALL_BINDINGS: Readonly<
Record
> = {
tap: "panel",
- doubleTap: "toggleTerminal",
+ doubleTap: "toggleAuxPanel",
longPress: "openSettings",
left: "newConversation",
right: "toggleSidebar",
up: "panel",
- down: null,
+ down: "toggleAuxPanel",
upLeft: "toggleSearch",
upRight: "nextTab",
- downLeft: null,
- downRight: null,
+ downLeft: "openChanges",
+ downRight: "openSessionDetails",
upThenLeft: "prevTab",
upThenRight: "reopenClosedTab",
upLeftThenRight: null,
From 7aca33f7fee9ce300c2799f8ff49d6fdcaf5e083 Mon Sep 17 00:00:00 2001
From: fengx
Date: Tue, 20 Oct 2026 11:59:51 +0800
Subject: [PATCH 18/18] fix(floating-ball): show tap/double-tap/long-press rows
in bindings UI
Batch v86 made the three click-scale gestures rebindable (double tap now
defaults to the right sidebar), but the settings list still filtered
them out, so users only saw the arrow gestures.
---
src/components/settings/appearance-settings.tsx | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/components/settings/appearance-settings.tsx b/src/components/settings/appearance-settings.tsx
index 1527a25a56..e4f5d39fd9 100644
--- a/src/components/settings/appearance-settings.tsx
+++ b/src/components/settings/appearance-settings.tsx
@@ -505,9 +505,7 @@ export function AppearanceSettings() {
{t("floatingBall.gestureBindings")}
- {FLOATING_BALL_GESTURES.filter(
- (g) => g !== "tap" && g !== "doubleTap" && g !== "longPress"
- ).map((gesture) => {
+ {FLOATING_BALL_GESTURES.map((gesture) => {
const override = floatingBallBindings[gesture]
const value = override ?? ""
return (