feat(webui): add project workspaces and access controls (#4007)

* feat(webui): add project workspaces and access controls

* feat(webui): add project workspaces and access controls

* refactor(tools): centralize workspace access resolution

* refactor(webui): remove unused workspace host state

* fix(webui): hide estimated file edit label

* fix(webui): clarify file edit deletion feedback

* fix(webui): label deleted file activity

* fix(webui): flatten file edit activity rows

* fix(core): remove path-only patch deletion

* fix(core): keep apply patch non-destructive

* refactor(webui): trim workspace host plumbing

* fix(tools): register exec with tools config
This commit is contained in:
Xubin Ren
2026-05-29 03:42:53 +08:00
committed by GitHub
parent 84428136e6
commit 3a420136bb
111 changed files with 9972 additions and 1822 deletions
+92 -42
View File
@@ -25,7 +25,9 @@
"section": "Sistema",
"restartHint": "Reinicia nanobot para aplicar los cambios de ejecución.",
"restart": "Reiniciar nanobot",
"restarting": "Reiniciando..."
"restarting": "Reiniciando...",
"restartEngine": "Reiniciar motor",
"restartingEngine": "Reiniciando motor..."
},
"restart": {
"completed": "Reinicio completado en {{seconds}} s."
@@ -40,25 +42,13 @@
},
"sidebar": {
"navigation": "Navegación de la barra lateral",
"globalActions": "Acciones globales",
"collapse": "Contraer barra lateral",
"toggleTheme": "Cambiar tema",
"home": "Inicio",
"newChat": "Nuevo chat",
"searchAria": "Buscar",
"viewOptions": "View",
"compactList": "Compact list",
"showPreviews": "Show previews",
"showTimestamps": "Show time",
"sortLabel": "Sort",
"sortUpdated": "Recently updated",
"sortCreated": "Recently created",
"sortTitle": "Title A-Z",
"searchPlaceholder": "Buscar",
"searchResults": "Resultados",
"noSearchResults": "No hay chats coincidentes.",
"recent": "Recientes",
"refreshSessions": "Actualizar sesiones",
"settings": "Configuración",
"language": {
"label": "Idioma",
@@ -80,9 +70,9 @@
"models": "Models",
"providers": "Providers",
"image": "Image",
"web": "Web",
"runtime": "Runtime",
"advanced": "Advanced",
"browser": "Web",
"runtime": "Sistema",
"advanced": "Security",
"cliApps": "Apps CLI",
"mcp": "MCP",
"apps": "Apps"
@@ -99,12 +89,13 @@
"webSearch": "Web search",
"webBehavior": "Behavior",
"identity": "Identity",
"safety": "Safety",
"webuiSafety": "Web safety",
"capabilities": "Capacidades",
"integrations": "Integrations",
"cliApps": "Apps CLI",
"mcp": "Servicios MCP",
"apps": "Apps"
"apps": "Apps",
"nativeHost": "App",
"hostSafety": "App safety"
},
"rows": {
"theme": "Tema",
@@ -137,22 +128,16 @@
"botName": "Bot name",
"botIcon": "Bot icon",
"timezone": "Timezone",
"toolHintMaxLength": "Tool hint length",
"workspacePath": "Workspace path",
"heartbeat": "Heartbeat",
"dream": "Dream",
"unifiedSession": "Unified session",
"restrictWorkspace": "Restrict to workspace",
"execTool": "Exec tool",
"execSandbox": "Exec sandbox",
"ssrfWhitelist": "SSRF whitelist",
"mcpServers": "MCP servers",
"pathAppend": "PATH append",
"configurationDocs": "Configuration docs",
"workspacePath": "Workspace predeterminado",
"localServiceAccess": "Local services",
"webuiDefaultAccess": "Default access",
"currentModel": "Modelo actual",
"brandLogos": "Logotipos de marca",
"cliAppsCatalog": "Catálogo de apps CLI",
"cliAppsFilter": "Filtro de apps CLI"
"cliAppsFilter": "Filtro de apps CLI",
"engine": "Motor",
"logs": "Registros",
"diagnostics": "Diagnóstico"
},
"help": {
"theme": "Cambia entre apariencia clara y oscura.",
@@ -175,17 +160,22 @@
"defaultAspectRatio": "Se usa cuando el prompt no elige una relación de aspecto.",
"defaultImageSize": "Sugerencia de tamaño enviada a los proveedores que la admiten.",
"maxImagesPerTurn": "Límite superior para una solicitud generate_image.",
"botName": "Shown in runtime surfaces that use the configured bot identity.",
"botIcon": "Short emoji or text shown beside the bot name.",
"timezone": "IANA timezone used by runtime context and schedules.",
"toolHintMaxLength": "Maximum characters shown in tool progress hints.",
"advancedReadOnly": "Advanced safety controls are read-only in WebUI. Edit config.json intentionally when needed.",
"botName": "Se muestra donde nanobot usa un nombre visible.",
"botIcon": "Emoji o texto corto mostrado junto al nombre del bot.",
"timezone": "Se usa para programaciones y respuestas sensibles al tiempo.",
"localServiceAccess": "Allow Full Access shell commands to reach localhost services.",
"webuiDefaultAccess": "Used by web chats without a project-specific permission.",
"securityManagedControls": "Web fetches always protect local, private, and metadata services. Core channel safety stays in config.json.",
"currentModel": "Elige el modelo que nanobot usará para las próximas respuestas.",
"selectedModelProvider": "Lo define el modelo seleccionado.",
"selectedModelValue": "Lo define el modelo seleccionado.",
"brandLogos": "Los logotipos se cargan desde los dominios de las marcas con una reserva de icono local.",
"cliAppsCatalog": "Explora CLIs de apps que nanobot puede ejecutar localmente.",
"cliAppsFilter": "Busca por app, categoría o capacidad."
"cliAppsFilter": "Busca por app, categoría o capacidad.",
"logs": "Abre la carpeta de registros del motor de escritorio.",
"diagnostics": "Exporta un pequeño informe de runtime para soporte.",
"localServiceAccessNative": "Allow Full Access shell commands to reach services on this Mac.",
"webuiDefaultAccessNative": "Used by native chats without a project-specific permission."
},
"values": {
"light": "Claro",
@@ -201,8 +191,12 @@
"expanded": "Expanded",
"on": "On",
"off": "Off",
"defaultPermission": "Default Permission",
"fullAccess": "Full Access",
"configured": "Configured",
"notConfigured": "Not configured"
"notConfigured": "Not configured",
"pending": "Pendiente",
"restartingEngine": "Reiniciando"
},
"status": {
"loading": "Cargando configuración...",
@@ -212,14 +206,24 @@
"savedRestart": "Guardado. Reinicia nanobot para aplicar.",
"restartAfterSaving": "Guarda los cambios y reinicia cuando estés listo.",
"savedRestartApply": "Guardado. Reinicia cuando estés listo.",
"imageProviderRestart": "Cambios del proveedor de imágenes guardados. Reinicia cuando estés listo."
"imageProviderRestart": "Cambios del proveedor de imágenes guardados. Reinicia cuando estés listo.",
"hostRestartAfterSaving": "Guarda los cambios y nanobot reiniciará su motor.",
"hostRestartPending": "Guardado. Reiniciando el motor cuando esté listo.",
"hostApiUnavailable": "Host actions are only available inside the native app.",
"logsOpened": "Opened logs folder.",
"logsOpenFailed": "Could not open logs folder.",
"diagnosticsExported": "Diagnostics exported to {{path}}.",
"diagnosticsExportFailed": "Could not export diagnostics."
},
"actions": {
"save": "Guardar",
"saving": "Guardando",
"edit": "Editar",
"cancel": "Cancelar",
"openDocs": "Open docs"
"open": "Abrir",
"export": "Exportar",
"opening": "Opening...",
"exporting": "Exporting..."
},
"byok": {
"description": "Usa tus propias claves de proveedor. Nanobot lee estos valores desde la configuración actual, y solo los proveedores configurados se pueden elegir en General.",
@@ -290,6 +294,7 @@
"newConfiguration": "Nueva configuración de modelo",
"newConfigurationHelp": "Guarda un proveedor y un modelo como una opción de un clic.",
"configurationName": "Nombre",
"configurationNameHelp": "Cambia el nombre de esta configuración de modelo guardada.",
"configurationNamePlaceholder": "Escritura rápida"
},
"timezone": {
@@ -397,6 +402,19 @@
"featured": "Destacadas",
"loading": "Cargando apps...",
"empty": "Ninguna app coincide con este filtro."
},
"oauth": {
"authentication": "OAuth authentication",
"signIn": "Sign in",
"signingIn": "Signing in...",
"signInAgain": "Sign in again",
"signOut": "Sign out",
"signedInAs": "Signed in as {{account}}",
"signInHelp": "Sign in from this device; no API key is stored in config.",
"signInRequired": "Sign in required",
"signInBeforeSaving": "Sign in before saving this OAuth provider as the active model provider.",
"signedIn": "Signed in",
"notSignedIn": "Not signed in"
}
},
"chat": {
@@ -404,7 +422,10 @@
"loading": "Cargando…",
"noSessions": "Todavía no hay sesiones.",
"showMore": "Mostrar {{count}} más",
"collapsed": "{{count}} chats ocultos",
"showLess": "Mostrar menos",
"actions": "Acciones del chat {{title}}",
"newInProject": "Iniciar un chat nuevo en {{project}}",
"activity": {
"running": "Agent running",
"complete": "Agent finished"
@@ -415,6 +436,9 @@
"renameTitle": "Rename chat",
"renameDescription": "Choose a local sidebar name for this chat.",
"renamePlaceholder": "Chat name",
"renameProjectTitle": "Rename project",
"renameProjectDescription": "Choose a local sidebar name for this project.",
"renameProjectPlaceholder": "Project name",
"renameSave": "Save",
"archive": "Archive",
"unarchive": "Unarchive",
@@ -425,6 +449,7 @@
"groups": {
"pinned": "Pinned",
"all": "Chats",
"projects": "Projects",
"today": "Today",
"yesterday": "Yesterday",
"earlier": "Earlier",
@@ -448,7 +473,12 @@
"thread": {
"loadingConversation": "Cargando conversación…",
"empty": {
"greeting": "¿Qué puedo hacer por ti?",
"greetings": {
"workOn": "¿En qué trabajamos juntos?",
"start": "¿Por dónde empezamos?",
"build": "¿Qué construimos hoy?",
"tackle": "¿Qué resolvemos juntos?"
},
"quickActions": {
"plan": {
"title": "Crear un plan de proyecto",
@@ -632,6 +662,13 @@
"mcpBadge": "MCP",
"cliDescription": "Usar @{{name}} como app CLI local",
"mcpDescription": "Usar @{{name}} como servidor MCP"
},
"workspace": {
"accessAria": "Workspace access mode",
"projectAria": "Elegir proyecto",
"projectPlaceholder": "Seleccionar proyecto",
"default": "Default Permission",
"full": "Full Access"
}
},
"scrollToBottom": "Desplazarse al final",
@@ -690,6 +727,19 @@
"messageTooBig": {
"title": "Mensaje demasiado grande",
"body": "El servidor rechazó tu último mensaje por superar el tamaño permitido. Quita algunas imágenes o usa archivos más pequeños y vuelve a enviarlo."
},
"workspaceScopeRejected": {
"title": "Workspace was not changed",
"body": "Nanobot kept the previous workspace because the requested project or access mode was rejected by the gateway."
}
},
"workspace": {
"dialog": {
"defaultProject": "Default workspace",
"manual": "Pegar ruta",
"manualPlaceholder": "/Users/name/project",
"usePath": "Use Path",
"absolutePathRequired": "Enter an absolute folder path on this machine."
}
}
}