Decouple bundled UI from runtime API and add remote instance tooling (#1228)
Add a packaged-client runtime boundary so the shared UI can talk to local, desktop, remote, and VS Code runtimes through the right transport instead of assuming one same-origin web server. Centralize OpenChamber-owned API access behind RuntimeAPIs, runtimeFetch, and runtime URL helpers, while keeping official OpenCode traffic on the SDK path. Support runtime switching, remote host selection, desktop client credentials, and headless connection links for pairing packaged clients with remote OpenChamber servers. Harden the new auth model by moving long-lived client tokens out of browser URLs, introducing short-lived scoped URL tokens for browser-owned transports, restricting URL-token access to explicit readable/realtime routes, and making client-token management session-scoped or self-scoped as appropriate. Update browser-owned assets and preview proxy flows to work with the split runtime model, including authenticated project icons, preview token propagation, CSP-safe preview bridge injection, and preview proxy auth that survives short-lived URL-token expiry. Tighten Electron security boundaries for packaged clients by gating privileged preload state to trusted origins and requiring explicit confirmation before connect deep-links import or switch remote runtimes. Also refresh agent guidance and project skills so future runtime/API, auth, preview, UI, CLI, settings, locale, and drag-to-reorder work follows the new architecture.
This commit is contained in:
committed by
GitHub
parent
a4314c189b
commit
2031e3b4a8
@@ -27,6 +27,94 @@ export const dict: Record<I18nKey, string> = {
|
||||
"layout.mainTab.files": "Arquivos",
|
||||
"layout.mainTab.terminal": "Terminal",
|
||||
"layout.mainTab.context": "Contexto",
|
||||
"mobile.nav.aria": "Navegação móvel",
|
||||
"mobile.nav.changes": "Alterações",
|
||||
"mobile.nav.settings": "Configurações",
|
||||
"mobile.surface.closeAria": "Fechar",
|
||||
"mobile.header.openMenuAria": "Abrir menu",
|
||||
"mobile.menu.titleAria": "Ferramentas do espaço de trabalho",
|
||||
"mobile.menu.files": "Arquivos",
|
||||
"mobile.menu.changes": "Alterações",
|
||||
"mobile.menu.settings": "Configurações",
|
||||
"mobile.sessions.newChatCta": "Novo chat em {project}",
|
||||
"mobile.sessions.dateGroup.today": "Hoje",
|
||||
"mobile.sessions.dateGroup.yesterday": "Ontem",
|
||||
"mobile.sessions.dateGroup.thisWeek": "Início desta semana",
|
||||
"mobile.sessions.dateGroup.older": "Mais antigos",
|
||||
"mobile.sessions.section.worktrees": "Worktrees",
|
||||
"mobile.sessions.section.otherProjects": "Trocar de projeto",
|
||||
"mobile.sessions.section.projects": "Projetos",
|
||||
"mobile.sessions.empty.noProjectsTitle": "Sem projetos",
|
||||
"mobile.sessions.empty.noProjectsDescription": "Adicione um projeto para começar a conversar com seu código.",
|
||||
"mobile.sessions.empty.noSessionsTitle": "Sem sessões",
|
||||
"mobile.sessions.empty.noSessionsDescription": "Inicie seu primeiro chat para vê-lo aqui.",
|
||||
"mobile.sessions.empty.searchTitle": "Sem resultados",
|
||||
"mobile.sessions.empty.searchDescription": "Tente outro termo de busca.",
|
||||
"mobile.sessions.showArchived": "Mostrar arquivadas ({count})",
|
||||
"mobile.sessions.hideArchived": "Ocultar arquivadas",
|
||||
"mobile.sessions.activeWorktreeAria": "Worktree ativa",
|
||||
"mobile.sessions.activeProjectAria": "Projeto ativo",
|
||||
"mobile.sessions.startNewChat": "Iniciar novo chat",
|
||||
"mobile.sessions.newChat": "Novo chat",
|
||||
"mobile.sessions.editOrder": "Reordenar projetos",
|
||||
"mobile.sessions.doneEditing": "Concluído",
|
||||
"mobile.sessions.editOrderHint": "Arraste a alça ou use as setas para reordenar os projetos. Toque na marca para finalizar.",
|
||||
"mobile.sessions.dragHandleAria": "Arrastar {label} para reordenar",
|
||||
"mobile.sessions.moveUpAria": "Mover {label} para cima",
|
||||
"mobile.sessions.moveDownAria": "Mover {label} para baixo",
|
||||
"mobile.sessions.removeProjectAria": "Remover {label}",
|
||||
"mobile.sessions.cancelRemoveProjectAria": "Cancelar remoção de {label}",
|
||||
"mobile.sessions.confirmRemoveProject": "Excluir",
|
||||
"mobile.sessions.confirmRemoveProjectAria": "Confirmar remoção de {label}",
|
||||
"mobile.sessions.toast.projectRemoved": "Removido {label}",
|
||||
"mobile.sessions.showMore": "Mostrar mais {count}",
|
||||
"mobile.sessions.search.section.sessions": "Sessões",
|
||||
"mobile.sessions.search.section.archived": "Arquivadas",
|
||||
"mobile.sessions.search.section.projects": "Projetos",
|
||||
"mobile.sessions.clearSearchAria": "Limpar busca",
|
||||
"mobile.header.noProject": "Selecione um projeto",
|
||||
"mobile.header.activeSession": "Sessão ativa",
|
||||
"mobile.header.noSession": "Nenhuma sessão ativa",
|
||||
"mobile.sessions.openSheetAria": "Abrir sessões e projetos",
|
||||
"mobile.sessions.closeSheetAria": "Fechar sessões e projetos",
|
||||
"mobile.sessions.sheet.title": "Sessões",
|
||||
"mobile.sessions.sheet.description": "Alterne projetos, abra sessões ou inicie um novo chat.",
|
||||
"mobile.sessions.search.placeholder": "Pesquisar sessões",
|
||||
"mobile.sessions.empty": "Nenhuma sessão encontrada.",
|
||||
"mobile.sessions.unassignedProject": "Outras sessões",
|
||||
"mobile.sessions.newSessionAria": "Iniciar uma nova sessão neste projeto",
|
||||
"mobile.sessions.untitled": "Sessão sem título",
|
||||
"mobile.sessions.project.sessionsSingle": "1 sessão",
|
||||
"mobile.sessions.project.sessionsPlural": "{count} sessões",
|
||||
"mobile.files.refreshAria": "Atualizar arquivos",
|
||||
"mobile.files.backToParentAria": "Voltar para {name}",
|
||||
"mobile.files.rootDirectory": "Arquivos do projeto",
|
||||
"mobile.files.search.placeholder": "Buscar arquivos",
|
||||
"mobile.files.search.empty": "Nenhum arquivo encontrado.",
|
||||
"mobile.files.parentDirectory": "Diretório pai",
|
||||
"mobile.files.empty.noDirectory": "Selecione um projeto para navegar pelos arquivos.",
|
||||
"mobile.files.empty.directory": "Este diretório está vazio.",
|
||||
"mobile.files.error.listFailed": "Falha ao carregar arquivos",
|
||||
"mobile.files.error.readUnavailable": "A prévia do arquivo não está disponível neste runtime.",
|
||||
"mobile.files.file.truncated": "Prévia do arquivo truncada para mobile.",
|
||||
"mobile.files.copyPathAria": "Copiar caminho do arquivo",
|
||||
"mobile.files.copyContent": "Copiar conteúdo",
|
||||
"mobile.files.copyContentAria": "Copiar conteúdo do arquivo",
|
||||
"mobile.files.toast.pathCopied": "Caminho copiado",
|
||||
"mobile.files.toast.contentCopied": "Conteúdo copiado",
|
||||
"mobile.files.toast.copyFailed": "Falha ao copiar",
|
||||
"mobile.changes.placeholder.title": "Alterações",
|
||||
"mobile.changes.placeholder.description": "Revisão da árvore de trabalho, sync e commits ficarão aqui.",
|
||||
"mobile.changes.branchLabel": "Branch: {branch}",
|
||||
"mobile.changes.noRemote": "Nenhum remote disponível",
|
||||
"mobile.changes.cleanDescription": "Não há arquivos alterados neste workspace.",
|
||||
"mobile.changes.diffDetail.subtitle": "Diff somente leitura",
|
||||
"mobile.changes.diffDetail.loadFailed": "Falha ao carregar diff",
|
||||
"mobile.changes.diffDetail.missingTitle": "O arquivo não está mais alterado",
|
||||
"mobile.changes.diffDetail.missingDescription": "Volte para Alterações e atualize a lista.",
|
||||
"mobile.changes.diffDetail.imageUnavailable": "Diffs de imagem ainda não estão disponíveis nas Alterações móveis.",
|
||||
"mobile.settings.placeholder.title": "Configurações",
|
||||
"mobile.settings.placeholder.description": "Configurações móveis de conexão e aplicativo ficarão aqui.",
|
||||
"layout.rightSidebar.git": "Git",
|
||||
"layout.rightSidebar.files": "Arquivos",
|
||||
"layout.rightSidebar.context": "Contexto",
|
||||
@@ -1125,6 +1213,12 @@ export const dict: Record<I18nKey, string> = {
|
||||
"header.services.refreshRateLimitsAria": "Atualizar limites de taxa",
|
||||
"header.services.noRateLimits": "Não há limites de taxa disponíveis.",
|
||||
"header.services.noRateLimitsReported": "Nenhum limite de taxa foi informado.",
|
||||
"header.services.remoteUpdate.title": "Atualização da instância remota",
|
||||
"header.services.remoteUpdate.checking": "Procurando atualizações...",
|
||||
"header.services.remoteUpdate.upToDate": "Esta instância está atualizada.",
|
||||
"header.services.remoteUpdate.available": "A versão {version} está disponível para esta instância.",
|
||||
"header.services.remoteUpdate.error": "Não foi possível verificar atualizações da instância remota",
|
||||
"header.services.remoteUpdate.actions.open": "Atualizar",
|
||||
"header.services.used": "Usado",
|
||||
"header.services.remaining": "Restante",
|
||||
"header.services.modelFamily.other": "Outro",
|
||||
@@ -2035,6 +2129,9 @@ export const dict: Record<I18nKey, string> = {
|
||||
"desktopHostSwitcher.header.currentDefaultColon": "Padrão atual:",
|
||||
"desktopHostSwitcher.status.connected": "Conectado",
|
||||
"desktopHostSwitcher.status.authRequired": "Autenticação obrigatória",
|
||||
"desktopHostSwitcher.status.checking": "Verificando",
|
||||
"desktopHostSwitcher.status.updateRecommended": "Atualização recomendada",
|
||||
"desktopHostSwitcher.status.incompatible": "Incompatível",
|
||||
"desktopHostSwitcher.status.wrongService": "Serviço incorreto",
|
||||
"desktopHostSwitcher.status.unreachable": "Inacessível",
|
||||
"desktopHostSwitcher.status.unknown": "Desconhecido",
|
||||
@@ -2221,6 +2318,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
"onboarding.remoteConnection.actions.chooseDifferentServer": "Escolher outro servidor",
|
||||
"onboarding.remoteConnection.actions.useLocalInstead": "Usar Local no lugar",
|
||||
"onboarding.remoteConnection.probe.authMessage": "O servidor exige autenticação. Você ainda pode se conectar, mas talvez precise fornecer credenciais.",
|
||||
"onboarding.remoteConnection.probe.updateRecommendedMessage": "Esta instância está executando uma versão diferente do OpenChamber. Você pode se conectar, mas atualize os dois apps se algo não funcionar.",
|
||||
"onboarding.remoteConnection.probe.incompatibleMessage": "O servidor está executando OpenChamber, mas não é compatível com esta versão do app. Atualize o OpenChamber no servidor e tente novamente.",
|
||||
"onboarding.remoteConnection.probe.wrongServiceMessage": "O servidor respondeu, mas não está executando OpenChamber. Verifique se o endereço aponta para um servidor OpenChamber.",
|
||||
"onboarding.remoteConnection.probe.unreachableMessage": "O servidor não está disponível. Revise sua conexão de rede e verifique o endereço do servidor.",
|
||||
"onboarding.desktopRecovery.localUnavailable.title": "OpenCode Local não disponível",
|
||||
@@ -2234,6 +2333,8 @@ export const dict: Record<I18nKey, string> = {
|
||||
"onboarding.desktopRecovery.remoteUnreachable.retry": "Tentar novamente conexão",
|
||||
"onboarding.desktopRecovery.incompatibleServer.title": "Servidor incompatível",
|
||||
"onboarding.desktopRecovery.incompatibleServer.description": "O servidor em \"{host}\" não está executando OpenChamber. Verifique se o endereço aponta para um servidor OpenChamber.",
|
||||
"onboarding.desktopRecovery.remoteIncompatible.title": "Atualização do servidor necessária",
|
||||
"onboarding.desktopRecovery.remoteIncompatible.description": "O servidor OpenChamber em \"{host}\" não é compatível com esta versão do app. Atualize o OpenChamber no servidor e tente novamente.",
|
||||
"onboarding.desktopRecovery.common.useLocal": "Usar Local",
|
||||
"onboarding.desktopRecovery.common.useRemote": "Usar remoto",
|
||||
"onboarding.desktopRecovery.actions.retrying": "Retentendo…",
|
||||
|
||||
Reference in New Issue
Block a user