feat: v0.7.4 时序语义修正 · 防线实效补漏 · 全量测试翻倍 — 2406 用例 + jsdom 组件测试全量回归
P1 修复面收口: - 超时三态区分(aborted→USER_INTERRUPT / ETIMEDOUT→TIMEOUT / 其余→ERROR), 根治"真实网络超时被误报为用户中断" - 流空闲超时统一(SSE/Ollama/Anthropic 读循环 60s 无数据抛 504 进重试通道) - 同会话并发 sendMessage 防重入(isRunning 守卫)+ 会话存在性预检 + 前置调用移入 try(ERROR+DONE 双事件保证,根治 isStreaming 假死) - 清空审计后 resetChainCache(根治 verifyChain 误报 TAMPERED) - DONE 不再提前清理 TRACE(TERMINATED 统一收尾,补全最终迭代录制) - IME 合成回车不发送(普通 Enter + Cmd/Ctrl+Enter 双分支)+ handleSend 闭包修复 P2 安全纵深: - preload 移除原始 electronAPI 暴露(渲染层零使用,关掉 XSS invoke 任意通道单点风险) - CORS 同源回显根治(仅当前浏览页面 Origin,did-navigate 同步) - MEMORY.md 命令保护正则扩展(括号/$/反引号/< 重定向边界 + 前导路径) - write_file append TOCTOU 统一(open 后 realpath 校验,新文件分支补漏) - 敏感键归一化(authKey 驼峰/连字符命中)+ MCP headers 鉴权值加密落库 - ReDoS 检测共享化(search_files/file_editor 统一拦截) - run_tests/lint_code 升风险 + 需确认 + npx --no-install(执行边界对齐 run_command) - MCP/SearXNG/llm.baseURL/updateFeedUrl 配置类 URL 高危目标校验(IPv6 去括号 + 十六进制映射解析 + 尾点剥离) P3 架构还债: - temperature/maxTokens 热生效(引擎/编排器/SubAgent 三处接线)+ setBatch 单事务落盘 - SessionRecorder flush 竞态根治(flushPromise 等待 + 超限内联落盘 + stopRecording async) - 内存收口(lastConsolidationBySession LRU / subTraces 清理 / 会话删除 disposeEngine) - i18n 全量收口(28 组件 + 353 key 双字典,状态标签改渲染时函数) - 死代码清理(updateTraceStep/HEADER_HEIGHT/void preA/失实注释) - 斜杠菜单 MUI 化 + 删除逻辑收敛 resetSessionState + Blob URL 统一释放 + 用户消息"仅保存"落库(saveMessage 透传前端 id 修复 id 错位) P4 能力演进: - 死循环检测拆分(驻留前置 + 乒乓后置带进度信号,合法交替不误报) - run-lock 30s 超时强制 abort(旧 run 卡死不无限排队) - RETRY 双通道 stream_reset(前端按 run 归属精确清空,根治重试文本重复) - FTS5 trigram 中文子串搜索(迁移 9 版本化 SCHEMA_VERSION=2,≤2 字符 LIKE 回退) - getContextWindow 兜底 1M→128K(未知模型防 413) 测试: - 855 → 2406 用例(+1551,2.8 倍):服务层 +325(含 MemoryManager 51 新用例)、 工具实体 +483、IPC/适配器 +390(含 OpenAI/Anthropic/Ollama 独立套件)、 纯函数表格化 +330;引入 jsdom + @testing-library(14 组件测试文件 249 用例) - 修复 R1(saveMessage id 透传)/ R2(stream_reset 精确归属)两个回归缺陷 - 遗留低危项清零:git-tools 顺序耦合 / web-fetch 真实时间退避 / slo 内存断言 / mcp-security 多余 skipIf / deepseek-balance 命名误导 / 组件 mock 注入脆弱性 版本: 0.7.4; README 同步(工具风险表/版本徽章); 依赖: 移除 @electron-toolkit/preload, 新增 jsdom/@testing-library(devDependencies 不打包) 回归: typecheck 双端 0 错误; ESLint 0/0; Electron ABI 全量 2406/2406 零跳过; 系统 Node 2110 通过 296 跳过(better-sqlite3 ABI)
This commit is contained in:
+841
-4
@@ -1,10 +1,13 @@
|
||||
/**
|
||||
* 集中文案字典(v0.6.4 P3-5 第一轮 → v0.7.2 P4-15 第二阶段)
|
||||
* 集中文案字典(v0.6.4 P3-5 第一轮 → v0.7.2 P4-15 第二阶段 → v0.7.4 P3-1 收口)
|
||||
*
|
||||
* 目标:把散落在数据层与核心组件的硬编码文案收敛为稳定 key。
|
||||
* 第二阶段覆盖:useAgentStream 终止原因(含此前硬编码的"执行出错")、
|
||||
* 确认弹框(ConfirmationDialog)、侧边栏(Sidebar)、状态栏(StatusBar)、
|
||||
* AgentMonitor 与通用按钮文案。组件层按此模式渐进迁移 —— 每迁一处,删一处字面量。
|
||||
* 第三阶段(v0.7.4 P3-1)覆盖渲染层全量迁移:CommandPalette / ContextMenu /
|
||||
* 聊天组件(AssistantMessage、ChatInput、MessageList、StreamingIndicator、ThoughtBlock、
|
||||
* ToolCallCard、ToolResultBlock、UserMessage)/ ErrorBoundary / DetailPanel / Header /
|
||||
* 各设置 Tab(Agent、Appearance、Logs、MCP、SearXNG、SettingsModal、Tools、Workspace)/
|
||||
* TaskList / Trace(TokenUsage、TraceStep、TraceViewer)/ WorkspaceViewer / useConfig。
|
||||
* 组件层按此模式渐进迁移 —— 每迁一处,删一处字面量。
|
||||
*/
|
||||
|
||||
import { registerTranslations } from './i18n';
|
||||
@@ -241,6 +244,419 @@ registerTranslations('zh-CN', {
|
||||
'onboarding.toast.saveFailed': '配置保存失败,请重试',
|
||||
'onboarding.toast.saveFailedWithReason': '保存配置失败:{{message}}',
|
||||
'onboarding.toast.folderFailed': '选择文件夹失败',
|
||||
|
||||
// ===== 通用(v0.7.4 P3-1 补充)=====
|
||||
'common.loading': '加载中...',
|
||||
|
||||
// ===== 命令面板(CommandPalette)=====
|
||||
'command.newSession': '新建会话',
|
||||
'command.newSessionDesc': '创建一个新的对话会话',
|
||||
'command.createFailed': '创建会话失败',
|
||||
'command.clearSession': '清空当前会话',
|
||||
'command.openSettings': '打开设置',
|
||||
'command.messageCount': '{{count}} 条消息',
|
||||
'command.searchPlaceholder': '搜索会话、命令...',
|
||||
'command.noMatch': '无匹配结果',
|
||||
'command.navHint': '↑↓ 导航',
|
||||
'command.selectHint': '↵ 选择',
|
||||
'command.closeHint': 'Esc 关闭',
|
||||
|
||||
// ===== 右键菜单(ContextMenu)=====
|
||||
'contextMenu.confirm': '确认',
|
||||
'contextMenu.prompt': '输入',
|
||||
'contextMenu.ok': '确定',
|
||||
'contextMenu.toast.copyFailed': '复制失败',
|
||||
'contextMenu.copy': '复制',
|
||||
'contextMenu.quote': '引用回复',
|
||||
'contextMenu.regenerate': '重新生成',
|
||||
'contextMenu.rename': '重命名',
|
||||
'contextMenu.renamePromptLabel': '新会话名称',
|
||||
'contextMenu.renamePromptTitle': '重命名会话',
|
||||
'contextMenu.toast.renameFailed': '重命名失败',
|
||||
'contextMenu.pin': '置顶',
|
||||
'contextMenu.unpin': '取消置顶',
|
||||
'contextMenu.toast.pinFailed': '置顶失败',
|
||||
'contextMenu.archive': '归档',
|
||||
'contextMenu.unarchive': '取消归档',
|
||||
'contextMenu.toast.archiveFailed': '归档失败',
|
||||
'contextMenu.exportJson': '导出 JSON',
|
||||
'contextMenu.exportMarkdown': '导出 Markdown',
|
||||
'contextMenu.sessionExportTitle': '会话导出',
|
||||
'contextMenu.toast.exportFailed': '导出失败',
|
||||
'contextMenu.deleteConfirmBody': '确定删除此会话?此操作不可撤销。',
|
||||
'contextMenu.toast.deleteFailed': '删除失败',
|
||||
|
||||
// ===== 聊天(chat / assistant / messageList / streaming / thought / toolCall / toolResult / userMessage)=====
|
||||
'chat.export.title': '会话导出',
|
||||
'assistant.thinking': '正在思考...',
|
||||
'assistant.thinkingLabel': '思考过程',
|
||||
'assistant.generating': '正在生成回复...',
|
||||
'assistant.toolCalls': '工具调用',
|
||||
'assistant.reply': '回复',
|
||||
'assistant.copy': '复制',
|
||||
'assistant.copied': '已复制',
|
||||
'messageList.subtitle': '生产级通用 AI Agent 智能体桌面应用',
|
||||
'messageList.emptyHint': 'Agent 就绪 · 选择一个 Provider 开始对话',
|
||||
'messageList.ariaLabel': '聊天消息列表',
|
||||
'streaming.connecting': '正在连接 AI...',
|
||||
'thought.thinkingLabel': '思考过程',
|
||||
'toolCall.status.pending': '等待中',
|
||||
'toolCall.status.executing': '执行中',
|
||||
'toolCall.status.success': '成功',
|
||||
'toolCall.status.error': '失败',
|
||||
'toolCall.status.blocked': '已阻止',
|
||||
'toolResult.title': '{{name}} 结果',
|
||||
'userMessage.saveOnly': '仅保存',
|
||||
'userMessage.saveAndResend': '保存并重发',
|
||||
'userMessage.resendHint': '重发将删除此消息之后的所有消息 · Ctrl+Enter',
|
||||
|
||||
// ===== 错误边界(ErrorBoundary)=====
|
||||
'errorBoundary.renderFailed': '组件渲染失败',
|
||||
'errorBoundary.unknownError': '未知错误',
|
||||
'errorBoundary.retry': '重试',
|
||||
|
||||
// ===== 详情面板(DetailPanel)=====
|
||||
'detailPanel.error.trace': 'Trace 渲染失败',
|
||||
'detailPanel.error.memory': 'Memory 渲染失败',
|
||||
'detailPanel.error.tasks': 'Tasks 渲染失败',
|
||||
'detailPanel.error.workspace': 'Workspace 渲染失败',
|
||||
|
||||
// ===== 顶栏(Header)=====
|
||||
'header.theme.light': '浅色主题',
|
||||
'header.theme.dark': '深色主题',
|
||||
'header.theme.auto': '跟随系统',
|
||||
'header.hideSidebar': '隐藏侧边栏',
|
||||
'header.showSidebar': '显示侧边栏',
|
||||
'header.hideDetail': '隐藏详情面板',
|
||||
'header.showDetail': '显示详情面板',
|
||||
'header.exitFocus': '退出专注模式',
|
||||
'header.enterFocus': '进入专注模式',
|
||||
'header.settings': '设置',
|
||||
|
||||
// ===== Agent 监视(AgentMonitor 补充)=====
|
||||
'monitor.iterations': ' · {{count}} 轮',
|
||||
|
||||
// ===== Agent 配置(AgentSettings)=====
|
||||
'settings.agent.title': 'Agent 配置',
|
||||
'settings.agent.maxIterations': '最大迭代次数',
|
||||
'settings.agent.totalTimeout': '总超时(秒)',
|
||||
'settings.agent.toolExecTimeout': '工具执行超时(秒)',
|
||||
'settings.agent.toolExecTimeoutHelper':
|
||||
'单个工具执行的最大时长,超时自动终止(最低 10 秒,无上限)',
|
||||
'settings.agent.confirmTimeout': '工具确认超时(秒)',
|
||||
'settings.agent.confirmTimeoutHelper': '用户未响应工具确认时,超时自动视为拒绝(30~600 秒)',
|
||||
'settings.agent.enableThinking': '启用思考模式',
|
||||
'settings.agent.thinkingEffort': '思考强度',
|
||||
'settings.agent.enableReflection': '启用反思阶段(REFLECTING)',
|
||||
'settings.agent.enableReflectionHelper':
|
||||
'每轮工具执行后进入反思状态,存在失败结果时记录告警(不阻断执行)',
|
||||
|
||||
// ===== 外观设置(AppearanceSettings)=====
|
||||
'settings.appearance.title': '外观',
|
||||
'settings.appearance.theme': '主题',
|
||||
'settings.appearance.dark': '深色',
|
||||
'settings.appearance.light': '浅色',
|
||||
'settings.appearance.auto': '跟随系统',
|
||||
'settings.appearance.locale': '界面语言',
|
||||
'settings.appearance.localeZhCN': '简体中文',
|
||||
'settings.appearance.localeEnUS': 'English',
|
||||
'settings.appearance.localeHelper':
|
||||
'切换即时生效;已迁移的界面(系统消息 / 工具确认弹框 / 侧边栏 / 状态栏 / Agent 状态区)将跟随所选语言显示',
|
||||
|
||||
// ===== 日志与数据(LogsSettings)=====
|
||||
'settings.logs.title': '日志与数据',
|
||||
'settings.logs.logLevel': '日志级别',
|
||||
'settings.logs.logFile': '日志文件',
|
||||
'settings.logs.pathLoading': '正在获取路径...',
|
||||
'settings.logs.pathUnavailable': '路径不可用',
|
||||
'settings.logs.openLogFolder': '打开日志文件夹',
|
||||
'settings.logs.copied': '已复制',
|
||||
'settings.logs.copyPath': '复制路径',
|
||||
'settings.logs.copyFailed': '复制失败',
|
||||
'settings.logs.openFailed': '打开失败: {{message}}',
|
||||
'settings.logs.logLevelHelper':
|
||||
'日志级别变更重启后生效。日志文件按日期滚动,旧日志保留在 logs 目录下。',
|
||||
'settings.logs.dataManagement': '数据管理',
|
||||
'settings.logs.exportAllData': '📦 导出全部数据(JSON)',
|
||||
'settings.logs.exportFailed': '导出失败: {{message}}',
|
||||
'settings.logs.exporting': '导出中...',
|
||||
'settings.logs.exportAuditJsonl': '📋 导出审计 (JSONL)',
|
||||
'settings.logs.exportAuditCsv': '📊 导出审计 (CSV)',
|
||||
'settings.logs.auditExported': '已导出 {{count}} 条审计记录',
|
||||
'settings.logs.auditExportFailed': '审计导出失败: {{message}}',
|
||||
'settings.logs.clearing': '清理中...',
|
||||
'settings.logs.clearSessions': '🗑️ 清理所有会话',
|
||||
'settings.logs.clearMemories': '🗑️ 清理所有记忆',
|
||||
'settings.logs.clearAuditLogs': '🗑️ 清理审计日志',
|
||||
'settings.logs.clear': '清理',
|
||||
'settings.logs.clearFailed': '失败: {{message}}',
|
||||
'settings.logs.confirmClearTitle': '确认清理',
|
||||
'settings.logs.confirmClearBody': '确定清理{{label}}?此操作不可撤销。',
|
||||
'settings.logs.cleared': '{{label}}已清理',
|
||||
'settings.logs.data.sessions': '所有会话',
|
||||
'settings.logs.data.memories': '所有记忆',
|
||||
'settings.logs.data.auditLogs': '审计日志',
|
||||
'settings.logs.traceFilesTitle': '会话录制文件(TRACE JSONL)',
|
||||
'settings.logs.traceStats':
|
||||
'{{count}} 个文件 · 共 {{size}}(保留策略:最近 200 个,启动时自动清理)',
|
||||
'settings.logs.statsLoading': '统计中...',
|
||||
'settings.logs.refreshStats': '刷新统计',
|
||||
'settings.logs.pruneOldFiles': '清理旧录制文件',
|
||||
'settings.logs.pruneDone': '已清理 {{count}} 个旧录制文件(保留最近 200 个)',
|
||||
'settings.logs.pruneFailed': '清理失败:{{message}}',
|
||||
'settings.logs.healthTitle': '运行健康(SLO / 健康检查)',
|
||||
'settings.logs.noSnapshot': '暂无快照',
|
||||
'settings.logs.health.errorRate': '请求错误率(5 分钟窗口)',
|
||||
'settings.logs.health.errorRateValue': '{{pct}}({{count}} 次请求)',
|
||||
'settings.logs.health.latency': '延迟 P50 / P95 / P99',
|
||||
'settings.logs.health.burnRate': 'SLO 燃烧速率(目标 99.9%)',
|
||||
'settings.logs.health.check': '健康检查',
|
||||
'settings.logs.health.allPassed': '全部通过',
|
||||
'settings.logs.health.abnormal': '异常:{{checks}}',
|
||||
'settings.logs.health.notRunYet': '启动后尚未执行(周期 60s)',
|
||||
'settings.logs.health.chainVerify': '审计日志链校验',
|
||||
'settings.logs.health.chainValid': '通过({{verified}}/{{total}} 条)',
|
||||
'settings.logs.health.chainTampered': '已篡改!首个异常记录 #{{index}}',
|
||||
'settings.logs.health.verifyChainBtn': '校验审计日志链',
|
||||
'settings.logs.verifyFailed': '校验失败:{{message}}',
|
||||
|
||||
// ===== MCP 服务(MCPSettings)=====
|
||||
'settings.mcp.title': 'MCP 服务',
|
||||
'settings.mcp.empty': '暂无 MCP 服务',
|
||||
'settings.mcp.toolCount': '{{count}} 工具',
|
||||
'settings.mcp.connect': '连接',
|
||||
'settings.mcp.disconnect': '断开',
|
||||
'settings.mcp.remove': '移除',
|
||||
'settings.mcp.add': '添加',
|
||||
'settings.mcp.addServer': '+ 添加 MCP 服务',
|
||||
'settings.mcp.serverName': '服务名称',
|
||||
'settings.mcp.localStdio': '本地 (stdio)',
|
||||
'settings.mcp.remoteHttp': '远程 (HTTP)',
|
||||
'settings.mcp.commandPlaceholder': '命令路径(如 npx / node / python)',
|
||||
'settings.mcp.argsPlaceholder': '参数 (空格分隔)',
|
||||
'settings.mcp.urlPlaceholder': 'Streamable HTTP URL(如 https://example.com/mcp)',
|
||||
'settings.mcp.headersPlaceholder':
|
||||
'自定义请求头 (JSON,可选),如 {"Authorization": "Bearer xxx"}',
|
||||
'settings.mcp.headersInvalid':
|
||||
'自定义请求头需为合法 JSON 对象,如 {"Authorization": "Bearer xxx"}',
|
||||
'settings.mcp.addFailed': '添加 MCP 服务失败',
|
||||
'settings.mcp.addFailedMsg': '添加 MCP 服务失败:{{message}}',
|
||||
'settings.mcp.removeFailed': '移除失败',
|
||||
'settings.mcp.removeFailedMsg': '移除失败:{{message}}',
|
||||
'settings.mcp.toggleFailed': '操作失败',
|
||||
'settings.mcp.toggleFailedMsg': '操作失败:{{message}}',
|
||||
'settings.mcp.removeConfirmTitle': '确认移除',
|
||||
'settings.mcp.removeConfirmBody': '确定移除 MCP 服务 "{{name}}"?此操作不可撤销。',
|
||||
|
||||
// ===== SearXNG 配置(SearXNGSettings)=====
|
||||
'settings.searxng.tabTitle': 'SearXNG',
|
||||
'settings.searxng.title': 'SearXNG 元搜索',
|
||||
'settings.searxng.description':
|
||||
'SearXNG 是开源元搜索引擎,支持 70+ 搜索引擎聚合。启用后替代内置四引擎搜索通道,未启用时回退到 Bing + 百度 + 搜狗 + 360 搜索。',
|
||||
'settings.searxng.enabled': '已启用',
|
||||
'settings.searxng.disabled': '未启用',
|
||||
'settings.searxng.enableAria': '启用 SearXNG',
|
||||
'settings.searxng.enable': '启用 SearXNG',
|
||||
'settings.searxng.urlLabel': 'API 地址',
|
||||
'settings.searxng.urlPlaceholder': '如 https://searxng.example.com',
|
||||
'settings.searxng.urlError': '需以 http:// 或 https:// 开头',
|
||||
'settings.searxng.urlHelper': '实例根地址(不含 /search 路径)',
|
||||
'settings.searxng.test': '测试连接',
|
||||
'settings.searxng.testSuccess': '连接成功({{latency}}ms)',
|
||||
'settings.searxng.testFailedHttp': '连接失败(HTTP {{code}})',
|
||||
'settings.searxng.enginesLabel': '搜索引擎(逗号分隔)',
|
||||
'settings.searxng.enginesPlaceholder': '如 google,bing,duckduckgo(留空使用实例默认)',
|
||||
'settings.searxng.language': '语言',
|
||||
'settings.searxng.langZhCN': '简体中文',
|
||||
'settings.searxng.langZhTW': '繁體中文',
|
||||
'settings.searxng.langAuto': '自动检测',
|
||||
'settings.searxng.safesearch': '安全搜索',
|
||||
'settings.searxng.safeOff': '关闭',
|
||||
'settings.searxng.safeMedium': '中等',
|
||||
'settings.searxng.safeStrict': '严格',
|
||||
'settings.searxng.timeRange': '时间范围',
|
||||
'settings.searxng.timeAny': '不限',
|
||||
'settings.searxng.timeDay': '一天',
|
||||
'settings.searxng.timeWeek': '一周',
|
||||
'settings.searxng.timeMonth': '一月',
|
||||
'settings.searxng.timeYear': '一年',
|
||||
'settings.searxng.format': '返回格式',
|
||||
'settings.searxng.formatJson': 'JSON(结构化解析)',
|
||||
'settings.searxng.formatHtml': 'HTML(原始网页)',
|
||||
'settings.searxng.maxResults': '最大结果数',
|
||||
'settings.searxng.maxResultsPlaceholder': '0 表示使用默认',
|
||||
'settings.searxng.fetchCount': '自动抓取条数',
|
||||
'settings.searxng.fetchCountPlaceholder': '0 表示由 AI 决定',
|
||||
'settings.searxng.fetchMode': '抓取类型',
|
||||
'settings.searxng.fetchSequential': '顺序抓取',
|
||||
'settings.searxng.fetchRandom': '随机抓取',
|
||||
'settings.searxng.authTitle': '认证设置',
|
||||
'settings.searxng.authType': '认证类型',
|
||||
'settings.searxng.authToken': 'Token',
|
||||
'settings.searxng.authUserPass': '用户名:密码',
|
||||
'settings.searxng.authTokenPlaceholder': '访问令牌原值',
|
||||
'settings.searxng.authUserPassPlaceholder': 'username:password',
|
||||
'settings.searxng.hideKey': '隐藏密钥',
|
||||
'settings.searxng.showKey': '显示密钥',
|
||||
'settings.searxng.authBearerHelper':
|
||||
'Bearer: 直接填写令牌原值,原样透传到 Authorization 头。建议配合 HTTPS 使用。',
|
||||
'settings.searxng.authBasicHelper':
|
||||
'Basic: 填写 username:password 明文串,系统自动 Base64 编码。必须配合 HTTPS 使用。',
|
||||
'settings.searxng.saved': 'SearXNG 配置已保存',
|
||||
'settings.searxng.saveFailed': '保存失败',
|
||||
'settings.searxng.toggleFailed': '开关保存失败',
|
||||
'settings.searxng.saving': '保存中...',
|
||||
'settings.searxng.saveChanges': '保存更改',
|
||||
'settings.searxng.dirty': '有未保存的修改',
|
||||
'settings.searxng.savedNotice': '已保存',
|
||||
'settings.searxng.loading': '正在读取配置...',
|
||||
|
||||
// ===== 设置弹窗(SettingsModal)=====
|
||||
'settings.title': '设置',
|
||||
'settings.tabs.workspace': '工作空间',
|
||||
'settings.tabs.llm': 'LLM 配置',
|
||||
'settings.tabs.agent': 'Agent 配置',
|
||||
'settings.tabs.tools': '工具管理',
|
||||
'settings.tabs.mcp': 'MCP 服务',
|
||||
'settings.tabs.searxng': 'SearXNG',
|
||||
'settings.tabs.appearance': '外观',
|
||||
'settings.tabs.logs': '日志与数据',
|
||||
'settings.error.workspace': '工作空间设置渲染失败',
|
||||
'settings.error.llm': 'LLM 配置渲染失败',
|
||||
'settings.error.agent': 'Agent 配置渲染失败',
|
||||
'settings.error.tools': '工具管理渲染失败',
|
||||
'settings.error.mcp': 'MCP 服务渲染失败',
|
||||
'settings.error.searxng': 'SearXNG 渲染失败',
|
||||
'settings.error.appearance': '外观设置渲染失败',
|
||||
'settings.error.logs': '日志与数据渲染失败',
|
||||
'settings.saveFailed': '配置保存失败',
|
||||
|
||||
// ===== 工具管理(ToolsSettings)=====
|
||||
'settings.tools.title': '工具管理',
|
||||
'settings.tools.toggleFailed': '切换工具失败',
|
||||
'settings.tools.autoExecFailed': '设置自动执行失败',
|
||||
'settings.tools.autoExecTitle': '自动执行工具',
|
||||
'settings.tools.autoExecCount': '{{count}} 个',
|
||||
'settings.tools.autoExecHelper':
|
||||
'已设为自动执行的工具将跳过用户确认步骤,直接执行。此设置跨会话持久化。',
|
||||
'settings.tools.noAutoExec': '暂无自动执行工具',
|
||||
'settings.tools.autoChip': '自动',
|
||||
'settings.tools.cancelAuto': '取消自动',
|
||||
'settings.tools.availableAutoExec': '可设为自动执行(当前需要确认)',
|
||||
'settings.tools.setAuto': '设为自动',
|
||||
'settings.tools.proxyTitle': '网络代理',
|
||||
'settings.tools.proxyLabel': '代理地址(可选)',
|
||||
'settings.tools.proxyPlaceholder': 'http://127.0.0.1:7890 或 socks5://…(留空直连)',
|
||||
'settings.tools.proxyError': '需以 http://、https://、socks5:// 或 socks4:// 开头',
|
||||
'settings.tools.proxyHelper':
|
||||
'应用于 Chromium 会话与主进程全部网络请求;未填时回退系统环境变量 HTTPS_PROXY。',
|
||||
|
||||
// ===== 工作空间设置(WorkspaceSettings)=====
|
||||
'settings.workspace.title': '工作空间',
|
||||
'settings.workspace.description':
|
||||
'工作空间是 Metona 的组织核心,包含 SOUL.md、MEMORY.md 两个必需文件。',
|
||||
'settings.workspace.placeholder': '~/MetonaWorkspaces/default/',
|
||||
'settings.workspace.checking': '校验中...',
|
||||
'settings.workspace.check': '校验',
|
||||
'settings.workspace.checkingInProgress': '正在校验工作空间...',
|
||||
'settings.workspace.invalidPath': '路径无效:{{reason}}',
|
||||
'settings.workspace.openInFileManager': '📂 在文件管理器中打开',
|
||||
'settings.workspace.openFolderFailed': '打开文件夹失败',
|
||||
'settings.workspace.targetWorkspace': '目标工作空间:{{path}}',
|
||||
'settings.workspace.newWorkspace':
|
||||
'新工作空间 — 切换后将自动创建 2 个必需文件(SOUL.md、MEMORY.md)',
|
||||
'settings.workspace.missingFiles':
|
||||
'已有目录但缺少 {{count}} 个文件:{{files}}。缺失文件将自动创建。',
|
||||
'settings.workspace.existingWorkspace':
|
||||
'已有工作空间 — 2 个必需文件均已就绪,将直接加载现有配置。',
|
||||
'settings.workspace.inheritFromCurrent': '从当前工作空间继承:',
|
||||
'settings.workspace.inheritSoul': 'SOUL.md(身份与角色定义)',
|
||||
'settings.workspace.inheritDatabase': '数据库 agent.db(会话/消息/记忆/Trace 历史记录)',
|
||||
'settings.workspace.inheritDatabaseHelper':
|
||||
'勾选后将复制当前工作空间的全部历史数据到新工作空间(通过 SQLite backup API 原子性导出)',
|
||||
'settings.workspace.memoryNotInherited': 'MEMORY.md 不继承(记忆与工作空间项目上下文绑定)',
|
||||
'settings.workspace.applying': '应用中...',
|
||||
'settings.workspace.confirmSwitch': '确认切换',
|
||||
'settings.workspace.restartHint': '修改工作空间路径后需重启应用生效。',
|
||||
'settings.workspace.switchedTitle': '工作空间已切换',
|
||||
'settings.workspace.switchedBody': '工作空间已更新为:',
|
||||
'settings.workspace.restartQuestion': '需要重启应用以加载新工作空间的配置和文件。是否立即重启?',
|
||||
'settings.workspace.restartLater': '稍后手动重启',
|
||||
'settings.workspace.restartNow': '立即重启',
|
||||
'settings.workspace.dbIntegrityFailed': '源数据库校验失败:{{message}}',
|
||||
'settings.workspace.dbCorrupted': '源数据库损坏({{detail}}),无法继承',
|
||||
'settings.workspace.dbIntegrityError': '源数据库校验异常:{{message}}',
|
||||
'settings.workspace.inheritPartialFailed': '部分文件继承失败:{{message}},请手动检查',
|
||||
'settings.workspace.switchFailed': '切换工作空间失败:{{message}}',
|
||||
|
||||
// ===== 任务列表(TaskList)=====
|
||||
'taskList.title': '任务列表',
|
||||
'taskList.count': '{{count}} 项',
|
||||
'taskList.addTask': '新增任务',
|
||||
'taskList.cancelAdd': '取消新增',
|
||||
'taskList.titlePlaceholder': '任务标题...',
|
||||
'taskList.creating': '...',
|
||||
'taskList.create': '创建',
|
||||
'taskList.cancelAddTask': '取消新增任务',
|
||||
'taskList.selectSession': '请先选择或创建会话',
|
||||
'taskList.titleRequired': '任务标题不能为空',
|
||||
'taskList.createFailed': '创建任务失败',
|
||||
'taskList.updateFailed': '更新任务失败',
|
||||
'taskList.deleteFailed': '删除任务失败',
|
||||
'taskList.loadFailed': '加载任务失败',
|
||||
'taskList.selectSessionHint': '请先选择会话',
|
||||
'taskList.empty': '暂无任务,点击 + 创建',
|
||||
'taskList.noDescription': '无描述',
|
||||
'taskList.status.pending': '待处理',
|
||||
'taskList.status.inProgress': '进行中',
|
||||
'taskList.status.completed': '已完成',
|
||||
'taskList.status.blocked': '阻塞',
|
||||
'taskList.status.cancelled': '已取消',
|
||||
'taskList.priority.low': '低',
|
||||
'taskList.priority.medium': '中',
|
||||
'taskList.priority.high': '高',
|
||||
'taskList.priority.critical': '紧急',
|
||||
|
||||
// ===== Token 统计(TokenUsage)=====
|
||||
'trace.token.usage': 'Token 用量',
|
||||
'trace.token.input': '输入',
|
||||
'trace.token.output': '输出',
|
||||
'trace.token.total': '累计消耗',
|
||||
'trace.token.context': '上下文占用',
|
||||
'trace.token.compressedSaved': '压缩节省',
|
||||
|
||||
// ===== Trace 步骤(TraceStep / constants)=====
|
||||
'trace.step.toolCalls': '工具调用',
|
||||
'trace.state.INIT': '初始化',
|
||||
'trace.state.THINKING': '思考',
|
||||
'trace.state.PARSING': '解析',
|
||||
'trace.state.EXECUTING': '执行',
|
||||
'trace.state.OBSERVING': '观察',
|
||||
'trace.state.REFLECTING': '反思',
|
||||
'trace.state.COMPRESSING': '压缩',
|
||||
'trace.state.TERMINATED': '终止',
|
||||
|
||||
// ===== Trace 视图(TraceViewer)=====
|
||||
'trace.viewer.rounds': '共 {{count}} 轮',
|
||||
'trace.viewer.waiting': '等待 Agent 活动...',
|
||||
'trace.viewer.roundNumber': '第 {{index}} 轮',
|
||||
'trace.viewer.inProgress': '进行中',
|
||||
'trace.viewer.completed': '已完成',
|
||||
'trace.viewer.steps': '{{count}} 步',
|
||||
|
||||
// ===== 工作空间浏览器(WorkspaceViewer)=====
|
||||
'workspace.currentWorkspace': '当前工作空间',
|
||||
'workspace.openInFileManager': '在文件管理器中打开',
|
||||
'workspace.showInFileManager': '在文件管理器中显示',
|
||||
'workspace.coreFiles': '核心文件({{count}}/{{total}})',
|
||||
'workspace.emptyFile': '(空文件)',
|
||||
'workspace.fileMissing': '文件不存在',
|
||||
'workspace.autoDirs': '自动目录',
|
||||
'workspace.dirFileCount': '{{count}} 个文件',
|
||||
'workspace.dirMissing': '不存在',
|
||||
'workspace.noData': '无数据',
|
||||
'workspace.loadFailed': '加载工作空间信息失败',
|
||||
'workspace.openFailed': '打开文件夹失败',
|
||||
});
|
||||
|
||||
registerTranslations('en-US', {
|
||||
@@ -478,4 +894,425 @@ registerTranslations('en-US', {
|
||||
'onboarding.toast.saveFailed': 'Failed to save configuration, please retry',
|
||||
'onboarding.toast.saveFailedWithReason': 'Failed to save configuration: {{message}}',
|
||||
'onboarding.toast.folderFailed': 'Failed to choose folder',
|
||||
|
||||
// ===== Common =====
|
||||
'common.loading': 'Loading...',
|
||||
|
||||
// ===== Command Palette =====
|
||||
'command.newSession': 'New Session',
|
||||
'command.newSessionDesc': 'Create a new chat session',
|
||||
'command.createFailed': 'Failed to create session',
|
||||
'command.clearSession': 'Clear current session',
|
||||
'command.openSettings': 'Open Settings',
|
||||
'command.messageCount': '{{count}} messages',
|
||||
'command.searchPlaceholder': 'Search sessions and commands...',
|
||||
'command.noMatch': 'No matches',
|
||||
'command.navHint': '↑↓ Navigate',
|
||||
'command.selectHint': '↵ Select',
|
||||
'command.closeHint': 'Esc Close',
|
||||
|
||||
// ===== Context Menu =====
|
||||
'contextMenu.confirm': 'Confirm',
|
||||
'contextMenu.prompt': 'Input',
|
||||
'contextMenu.ok': 'OK',
|
||||
'contextMenu.toast.copyFailed': 'Copy failed',
|
||||
'contextMenu.copy': 'Copy',
|
||||
'contextMenu.quote': 'Quote reply',
|
||||
'contextMenu.regenerate': 'Regenerate',
|
||||
'contextMenu.rename': 'Rename',
|
||||
'contextMenu.renamePromptLabel': 'New session name',
|
||||
'contextMenu.renamePromptTitle': 'Rename Session',
|
||||
'contextMenu.toast.renameFailed': 'Rename failed',
|
||||
'contextMenu.pin': 'Pin',
|
||||
'contextMenu.unpin': 'Unpin',
|
||||
'contextMenu.toast.pinFailed': 'Pin failed',
|
||||
'contextMenu.archive': 'Archive',
|
||||
'contextMenu.unarchive': 'Unarchive',
|
||||
'contextMenu.toast.archiveFailed': 'Archive failed',
|
||||
'contextMenu.exportJson': 'Export JSON',
|
||||
'contextMenu.exportMarkdown': 'Export Markdown',
|
||||
'contextMenu.sessionExportTitle': 'Session Export',
|
||||
'contextMenu.toast.exportFailed': 'Export failed',
|
||||
'contextMenu.deleteConfirmBody': 'Delete this session? This cannot be undone.',
|
||||
'contextMenu.toast.deleteFailed': 'Delete failed',
|
||||
|
||||
// ===== Chat / assistant / messageList / streaming / thought / toolCall / toolResult / userMessage =====
|
||||
'chat.export.title': 'Session Export',
|
||||
'assistant.thinking': 'Thinking...',
|
||||
'assistant.thinkingLabel': 'Thought process',
|
||||
'assistant.generating': 'Generating reply...',
|
||||
'assistant.toolCalls': 'Tool calls',
|
||||
'assistant.reply': 'Reply',
|
||||
'assistant.copy': 'Copy',
|
||||
'assistant.copied': 'Copied',
|
||||
'messageList.subtitle': 'A production-grade AI Agent desktop app',
|
||||
'messageList.emptyHint': 'Agent ready · pick a provider to start chatting',
|
||||
'messageList.ariaLabel': 'Chat message list',
|
||||
'streaming.connecting': 'Connecting to AI...',
|
||||
'thought.thinkingLabel': 'Thought process',
|
||||
'toolCall.status.pending': 'Waiting',
|
||||
'toolCall.status.executing': 'Executing',
|
||||
'toolCall.status.success': 'Success',
|
||||
'toolCall.status.error': 'Failed',
|
||||
'toolCall.status.blocked': 'Blocked',
|
||||
'toolResult.title': '{{name}} result',
|
||||
'userMessage.saveOnly': 'Save only',
|
||||
'userMessage.saveAndResend': 'Save & resend',
|
||||
'userMessage.resendHint': 'Resending deletes all messages after this one · Ctrl+Enter',
|
||||
|
||||
// ===== Error Boundary =====
|
||||
'errorBoundary.renderFailed': 'Component render failed',
|
||||
'errorBoundary.unknownError': 'Unknown error',
|
||||
'errorBoundary.retry': 'Retry',
|
||||
|
||||
// ===== Detail Panel =====
|
||||
'detailPanel.error.trace': 'Failed to render Trace',
|
||||
'detailPanel.error.memory': 'Failed to render Memory',
|
||||
'detailPanel.error.tasks': 'Failed to render Tasks',
|
||||
'detailPanel.error.workspace': 'Failed to render Workspace',
|
||||
|
||||
// ===== Header =====
|
||||
'header.theme.light': 'Light theme',
|
||||
'header.theme.dark': 'Dark theme',
|
||||
'header.theme.auto': 'System theme',
|
||||
'header.hideSidebar': 'Hide sidebar',
|
||||
'header.showSidebar': 'Show sidebar',
|
||||
'header.hideDetail': 'Hide detail panel',
|
||||
'header.showDetail': 'Show detail panel',
|
||||
'header.exitFocus': 'Exit focus mode',
|
||||
'header.enterFocus': 'Enter focus mode',
|
||||
'header.settings': 'Settings',
|
||||
|
||||
// ===== Agent Monitor (supplement) =====
|
||||
'monitor.iterations': ' · {{count}} round(s)',
|
||||
|
||||
// ===== Agent Settings =====
|
||||
'settings.agent.title': 'Agent Configuration',
|
||||
'settings.agent.maxIterations': 'Max iterations',
|
||||
'settings.agent.totalTimeout': 'Total timeout (seconds)',
|
||||
'settings.agent.toolExecTimeout': 'Tool execution timeout (seconds)',
|
||||
'settings.agent.toolExecTimeoutHelper':
|
||||
'Maximum duration for a single tool call; auto-terminated on timeout (min 10s, no upper limit)',
|
||||
'settings.agent.confirmTimeout': 'Tool confirmation timeout (seconds)',
|
||||
'settings.agent.confirmTimeoutHelper':
|
||||
'If the user does not respond to a tool confirmation, it is auto-denied after the timeout (30–600s)',
|
||||
'settings.agent.enableThinking': 'Enable thinking mode',
|
||||
'settings.agent.thinkingEffort': 'Thinking effort',
|
||||
'settings.agent.enableReflection': 'Enable reflection phase (REFLECTING)',
|
||||
'settings.agent.enableReflectionHelper':
|
||||
'Enters a reflection state after each round of tool execution; logs warnings on failed results (does not block execution)',
|
||||
|
||||
// ===== Appearance Settings =====
|
||||
'settings.appearance.title': 'Appearance',
|
||||
'settings.appearance.theme': 'Theme',
|
||||
'settings.appearance.dark': 'Dark',
|
||||
'settings.appearance.light': 'Light',
|
||||
'settings.appearance.auto': 'System',
|
||||
'settings.appearance.locale': 'Interface language',
|
||||
'settings.appearance.localeZhCN': '简体中文',
|
||||
'settings.appearance.localeEnUS': 'English',
|
||||
'settings.appearance.localeHelper':
|
||||
'Takes effect immediately; migrated UI (system messages / tool confirmation dialog / sidebar / status bar / agent status) follows the selected language',
|
||||
|
||||
// ===== Logs & Data Settings =====
|
||||
'settings.logs.title': 'Logs & Data',
|
||||
'settings.logs.logLevel': 'Log level',
|
||||
'settings.logs.logFile': 'Log file',
|
||||
'settings.logs.pathLoading': 'Fetching path...',
|
||||
'settings.logs.pathUnavailable': 'Path unavailable',
|
||||
'settings.logs.openLogFolder': 'Open log folder',
|
||||
'settings.logs.copied': 'Copied',
|
||||
'settings.logs.copyPath': 'Copy path',
|
||||
'settings.logs.copyFailed': 'Copy failed',
|
||||
'settings.logs.openFailed': 'Failed to open: {{message}}',
|
||||
'settings.logs.logLevelHelper':
|
||||
'Log level changes take effect after restart. Log files rotate by date; old logs are kept in the logs directory.',
|
||||
'settings.logs.dataManagement': 'Data management',
|
||||
'settings.logs.exportAllData': '📦 Export all data (JSON)',
|
||||
'settings.logs.exportFailed': 'Export failed: {{message}}',
|
||||
'settings.logs.exporting': 'Exporting...',
|
||||
'settings.logs.exportAuditJsonl': '📋 Export audit (JSONL)',
|
||||
'settings.logs.exportAuditCsv': '📊 Export audit (CSV)',
|
||||
'settings.logs.auditExported': 'Exported {{count}} audit record(s)',
|
||||
'settings.logs.auditExportFailed': 'Audit export failed: {{message}}',
|
||||
'settings.logs.clearing': 'Clearing...',
|
||||
'settings.logs.clearSessions': '🗑️ Clear all sessions',
|
||||
'settings.logs.clearMemories': '🗑️ Clear all memories',
|
||||
'settings.logs.clearAuditLogs': '🗑️ Clear audit logs',
|
||||
'settings.logs.clear': 'Clear',
|
||||
'settings.logs.clearFailed': 'Failed: {{message}}',
|
||||
'settings.logs.confirmClearTitle': 'Confirm clear',
|
||||
'settings.logs.confirmClearBody': 'Clear {{label}}? This cannot be undone.',
|
||||
'settings.logs.cleared': '{{label}} cleared',
|
||||
'settings.logs.data.sessions': 'all sessions',
|
||||
'settings.logs.data.memories': 'all memories',
|
||||
'settings.logs.data.auditLogs': 'audit logs',
|
||||
'settings.logs.traceFilesTitle': 'Session recording files (TRACE JSONL)',
|
||||
'settings.logs.traceStats':
|
||||
'{{count}} file(s) · {{size}} total (retention: last 200, auto-cleaned on startup)',
|
||||
'settings.logs.statsLoading': 'Computing...',
|
||||
'settings.logs.refreshStats': 'Refresh stats',
|
||||
'settings.logs.pruneOldFiles': 'Clear old recordings',
|
||||
'settings.logs.pruneDone': 'Cleared {{count}} old recording file(s) (keeping the last 200)',
|
||||
'settings.logs.pruneFailed': 'Clear failed: {{message}}',
|
||||
'settings.logs.healthTitle': 'Runtime health (SLO / health checks)',
|
||||
'settings.logs.noSnapshot': 'No snapshot yet',
|
||||
'settings.logs.health.errorRate': 'Request error rate (5-min window)',
|
||||
'settings.logs.health.errorRateValue': '{{pct}} ({{count}} requests)',
|
||||
'settings.logs.health.latency': 'Latency P50 / P95 / P99',
|
||||
'settings.logs.health.burnRate': 'SLO burn rate (target 99.9%)',
|
||||
'settings.logs.health.check': 'Health checks',
|
||||
'settings.logs.health.allPassed': 'All passed',
|
||||
'settings.logs.health.abnormal': 'Abnormal: {{checks}}',
|
||||
'settings.logs.health.notRunYet': 'Not run since startup (interval 60s)',
|
||||
'settings.logs.health.chainVerify': 'Audit log chain verification',
|
||||
'settings.logs.health.chainValid': 'Passed ({{verified}}/{{total}})',
|
||||
'settings.logs.health.chainTampered': 'Tampered! First anomaly at record #{{index}}',
|
||||
'settings.logs.health.verifyChainBtn': 'Verify audit chain',
|
||||
'settings.logs.verifyFailed': 'Verification failed: {{message}}',
|
||||
|
||||
// ===== MCP Settings =====
|
||||
'settings.mcp.title': 'MCP Services',
|
||||
'settings.mcp.empty': 'No MCP servers yet',
|
||||
'settings.mcp.toolCount': '{{count}} tools',
|
||||
'settings.mcp.connect': 'Connect',
|
||||
'settings.mcp.disconnect': 'Disconnect',
|
||||
'settings.mcp.remove': 'Remove',
|
||||
'settings.mcp.add': 'Add',
|
||||
'settings.mcp.addServer': '+ Add MCP server',
|
||||
'settings.mcp.serverName': 'Server name',
|
||||
'settings.mcp.localStdio': 'Local (stdio)',
|
||||
'settings.mcp.remoteHttp': 'Remote (HTTP)',
|
||||
'settings.mcp.commandPlaceholder': 'Command path (e.g. npx / node / python)',
|
||||
'settings.mcp.argsPlaceholder': 'Arguments (space-separated)',
|
||||
'settings.mcp.urlPlaceholder': 'Streamable HTTP URL (e.g. https://example.com/mcp)',
|
||||
'settings.mcp.headersPlaceholder':
|
||||
'Custom headers (JSON, optional), e.g. {"Authorization": "Bearer xxx"}',
|
||||
'settings.mcp.headersInvalid':
|
||||
'Custom headers must be a valid JSON object, e.g. {"Authorization": "Bearer xxx"}',
|
||||
'settings.mcp.addFailed': 'Failed to add MCP server',
|
||||
'settings.mcp.addFailedMsg': 'Failed to add MCP server: {{message}}',
|
||||
'settings.mcp.removeFailed': 'Remove failed',
|
||||
'settings.mcp.removeFailedMsg': 'Remove failed: {{message}}',
|
||||
'settings.mcp.toggleFailed': 'Operation failed',
|
||||
'settings.mcp.toggleFailedMsg': 'Operation failed: {{message}}',
|
||||
'settings.mcp.removeConfirmTitle': 'Confirm removal',
|
||||
'settings.mcp.removeConfirmBody': 'Remove MCP server "{{name}}"? This cannot be undone.',
|
||||
|
||||
// ===== SearXNG Settings =====
|
||||
'settings.searxng.tabTitle': 'SearXNG',
|
||||
'settings.searxng.title': 'SearXNG Meta Search',
|
||||
'settings.searxng.description':
|
||||
'SearXNG is an open-source metasearch engine aggregating 70+ search engines. When enabled it replaces the built-in four-engine channel; otherwise it falls back to Bing + Baidu + Sogou + 360.',
|
||||
'settings.searxng.enabled': 'Enabled',
|
||||
'settings.searxng.disabled': 'Disabled',
|
||||
'settings.searxng.enableAria': 'Enable SearXNG',
|
||||
'settings.searxng.enable': 'Enable SearXNG',
|
||||
'settings.searxng.urlLabel': 'API URL',
|
||||
'settings.searxng.urlPlaceholder': 'e.g. https://searxng.example.com',
|
||||
'settings.searxng.urlError': 'Must start with http:// or https://',
|
||||
'settings.searxng.urlHelper': 'Instance root URL (without the /search path)',
|
||||
'settings.searxng.test': 'Test connection',
|
||||
'settings.searxng.testSuccess': 'Connection successful ({{latency}}ms)',
|
||||
'settings.searxng.testFailedHttp': 'Connection failed (HTTP {{code}})',
|
||||
'settings.searxng.enginesLabel': 'Search engines (comma-separated)',
|
||||
'settings.searxng.enginesPlaceholder':
|
||||
'e.g. google,bing,duckduckgo (empty uses instance default)',
|
||||
'settings.searxng.language': 'Language',
|
||||
'settings.searxng.langZhCN': '简体中文',
|
||||
'settings.searxng.langZhTW': '繁體中文',
|
||||
'settings.searxng.langAuto': 'Auto-detect',
|
||||
'settings.searxng.safesearch': 'Safe search',
|
||||
'settings.searxng.safeOff': 'Off',
|
||||
'settings.searxng.safeMedium': 'Moderate',
|
||||
'settings.searxng.safeStrict': 'Strict',
|
||||
'settings.searxng.timeRange': 'Time range',
|
||||
'settings.searxng.timeAny': 'Any',
|
||||
'settings.searxng.timeDay': 'A day',
|
||||
'settings.searxng.timeWeek': 'A week',
|
||||
'settings.searxng.timeMonth': 'A month',
|
||||
'settings.searxng.timeYear': 'A year',
|
||||
'settings.searxng.format': 'Result format',
|
||||
'settings.searxng.formatJson': 'JSON (structured parsing)',
|
||||
'settings.searxng.formatHtml': 'HTML (raw page)',
|
||||
'settings.searxng.maxResults': 'Max results',
|
||||
'settings.searxng.maxResultsPlaceholder': '0 uses the default',
|
||||
'settings.searxng.fetchCount': 'Auto-fetch count',
|
||||
'settings.searxng.fetchCountPlaceholder': '0 lets the AI decide',
|
||||
'settings.searxng.fetchMode': 'Fetch mode',
|
||||
'settings.searxng.fetchSequential': 'Sequential fetch',
|
||||
'settings.searxng.fetchRandom': 'Random fetch',
|
||||
'settings.searxng.authTitle': 'Authentication',
|
||||
'settings.searxng.authType': 'Auth type',
|
||||
'settings.searxng.authToken': 'Token',
|
||||
'settings.searxng.authUserPass': 'Username:password',
|
||||
'settings.searxng.authTokenPlaceholder': 'Raw access token',
|
||||
'settings.searxng.authUserPassPlaceholder': 'username:password',
|
||||
'settings.searxng.hideKey': 'Hide key',
|
||||
'settings.searxng.showKey': 'Show key',
|
||||
'settings.searxng.authBearerHelper':
|
||||
'Bearer: paste the raw token; it is passed through to the Authorization header. Recommended with HTTPS.',
|
||||
'settings.searxng.authBasicHelper':
|
||||
'Basic: enter a plaintext username:password pair; the app Base64-encodes it. HTTPS is required.',
|
||||
'settings.searxng.saved': 'SearXNG configuration saved',
|
||||
'settings.searxng.saveFailed': 'Save failed',
|
||||
'settings.searxng.toggleFailed': 'Failed to save the toggle',
|
||||
'settings.searxng.saving': 'Saving...',
|
||||
'settings.searxng.saveChanges': 'Save changes',
|
||||
'settings.searxng.dirty': 'You have unsaved changes',
|
||||
'settings.searxng.savedNotice': 'Saved',
|
||||
'settings.searxng.loading': 'Loading configuration...',
|
||||
|
||||
// ===== Settings Modal =====
|
||||
'settings.title': 'Settings',
|
||||
'settings.tabs.workspace': 'Workspace',
|
||||
'settings.tabs.llm': 'LLM Configuration',
|
||||
'settings.tabs.agent': 'Agent Configuration',
|
||||
'settings.tabs.tools': 'Tools',
|
||||
'settings.tabs.mcp': 'MCP Services',
|
||||
'settings.tabs.searxng': 'SearXNG',
|
||||
'settings.tabs.appearance': 'Appearance',
|
||||
'settings.tabs.logs': 'Logs & Data',
|
||||
'settings.error.workspace': 'Failed to render workspace settings',
|
||||
'settings.error.llm': 'Failed to render LLM settings',
|
||||
'settings.error.agent': 'Failed to render agent settings',
|
||||
'settings.error.tools': 'Failed to render tool settings',
|
||||
'settings.error.mcp': 'Failed to render MCP settings',
|
||||
'settings.error.searxng': 'Failed to render SearXNG settings',
|
||||
'settings.error.appearance': 'Failed to render appearance settings',
|
||||
'settings.error.logs': 'Failed to render logs & data settings',
|
||||
'settings.saveFailed': 'Failed to save configuration',
|
||||
|
||||
// ===== Tools Settings =====
|
||||
'settings.tools.title': 'Tools',
|
||||
'settings.tools.toggleFailed': 'Failed to toggle tool',
|
||||
'settings.tools.autoExecFailed': 'Failed to set auto-execute',
|
||||
'settings.tools.autoExecTitle': 'Auto-execute tools',
|
||||
'settings.tools.autoExecCount': '{{count}}',
|
||||
'settings.tools.autoExecHelper':
|
||||
'Tools set to auto-execute skip the user confirmation step and run directly. This setting persists across sessions.',
|
||||
'settings.tools.noAutoExec': 'No auto-execute tools yet',
|
||||
'settings.tools.autoChip': 'Auto',
|
||||
'settings.tools.cancelAuto': 'Cancel auto',
|
||||
'settings.tools.availableAutoExec':
|
||||
'Available for auto-execute (currently requires confirmation)',
|
||||
'settings.tools.setAuto': 'Set auto',
|
||||
'settings.tools.proxyTitle': 'Network proxy',
|
||||
'settings.tools.proxyLabel': 'Proxy URL (optional)',
|
||||
'settings.tools.proxyPlaceholder': 'http://127.0.0.1:7890 or socks5://… (empty = direct)',
|
||||
'settings.tools.proxyError': 'Must start with http://, https://, socks5:// or socks4://',
|
||||
'settings.tools.proxyHelper':
|
||||
'Applies to all network requests from the Chromium session and the main process; falls back to the HTTPS_PROXY environment variable when empty.',
|
||||
|
||||
// ===== Workspace Settings =====
|
||||
'settings.workspace.title': 'Workspace',
|
||||
'settings.workspace.description':
|
||||
"The workspace is Metona's organizational core, containing the two required files SOUL.md and MEMORY.md.",
|
||||
'settings.workspace.placeholder': '~/MetonaWorkspaces/default/',
|
||||
'settings.workspace.checking': 'Checking...',
|
||||
'settings.workspace.check': 'Check',
|
||||
'settings.workspace.checkingInProgress': 'Checking workspace...',
|
||||
'settings.workspace.invalidPath': 'Invalid path: {{reason}}',
|
||||
'settings.workspace.openInFileManager': '📂 Open in file manager',
|
||||
'settings.workspace.openFolderFailed': 'Failed to open folder',
|
||||
'settings.workspace.targetWorkspace': 'Target workspace: {{path}}',
|
||||
'settings.workspace.newWorkspace':
|
||||
'New workspace — the 2 required files (SOUL.md, MEMORY.md) will be auto-created on switch',
|
||||
'settings.workspace.missingFiles':
|
||||
'Directory exists but {{count}} file(s) are missing: {{files}}. Missing files will be auto-created.',
|
||||
'settings.workspace.existingWorkspace':
|
||||
'Existing workspace — the 2 required files are ready; existing configuration will be loaded.',
|
||||
'settings.workspace.inheritFromCurrent': 'Inherit from the current workspace:',
|
||||
'settings.workspace.inheritSoul': 'SOUL.md (identity & role definition)',
|
||||
'settings.workspace.inheritDatabase':
|
||||
'Database agent.db (sessions/messages/memories/Trace history)',
|
||||
'settings.workspace.inheritDatabaseHelper':
|
||||
'When checked, all history from the current workspace is copied to the new one (exported atomically via the SQLite backup API)',
|
||||
'settings.workspace.memoryNotInherited':
|
||||
'MEMORY.md is not inherited (memories are bound to the workspace project context)',
|
||||
'settings.workspace.applying': 'Applying...',
|
||||
'settings.workspace.confirmSwitch': 'Confirm switch',
|
||||
'settings.workspace.restartHint':
|
||||
'Changing the workspace path requires an app restart to take effect.',
|
||||
'settings.workspace.switchedTitle': 'Workspace switched',
|
||||
'settings.workspace.switchedBody': 'The workspace has been updated to:',
|
||||
'settings.workspace.restartQuestion':
|
||||
'An app restart is required to load the new workspace configuration and files. Restart now?',
|
||||
'settings.workspace.restartLater': 'Restart later',
|
||||
'settings.workspace.restartNow': 'Restart now',
|
||||
'settings.workspace.dbIntegrityFailed': 'Source database verification failed: {{message}}',
|
||||
'settings.workspace.dbCorrupted': 'Source database is corrupted ({{detail}}); cannot inherit',
|
||||
'settings.workspace.dbIntegrityError': 'Source database verification error: {{message}}',
|
||||
'settings.workspace.inheritPartialFailed':
|
||||
'Some files failed to inherit: {{message}} — check manually',
|
||||
'settings.workspace.switchFailed': 'Failed to switch workspace: {{message}}',
|
||||
|
||||
// ===== Task List =====
|
||||
'taskList.title': 'Tasks',
|
||||
'taskList.count': '{{count}} item(s)',
|
||||
'taskList.addTask': 'Add task',
|
||||
'taskList.cancelAdd': 'Cancel add',
|
||||
'taskList.titlePlaceholder': 'Task title...',
|
||||
'taskList.creating': '...',
|
||||
'taskList.create': 'Create',
|
||||
'taskList.cancelAddTask': 'Cancel adding task',
|
||||
'taskList.selectSession': 'Select or create a session first',
|
||||
'taskList.titleRequired': 'Task title cannot be empty',
|
||||
'taskList.createFailed': 'Failed to create task',
|
||||
'taskList.updateFailed': 'Failed to update task',
|
||||
'taskList.deleteFailed': 'Failed to delete task',
|
||||
'taskList.loadFailed': 'Failed to load tasks',
|
||||
'taskList.selectSessionHint': 'Select a session first',
|
||||
'taskList.empty': 'No tasks yet — click + to create',
|
||||
'taskList.noDescription': 'No description',
|
||||
'taskList.status.pending': 'Pending',
|
||||
'taskList.status.inProgress': 'In progress',
|
||||
'taskList.status.completed': 'Completed',
|
||||
'taskList.status.blocked': 'Blocked',
|
||||
'taskList.status.cancelled': 'Cancelled',
|
||||
'taskList.priority.low': 'Low',
|
||||
'taskList.priority.medium': 'Medium',
|
||||
'taskList.priority.high': 'High',
|
||||
'taskList.priority.critical': 'Critical',
|
||||
|
||||
// ===== Token Usage =====
|
||||
'trace.token.usage': 'Token Usage',
|
||||
'trace.token.input': 'Input',
|
||||
'trace.token.output': 'Output',
|
||||
'trace.token.total': 'Total usage',
|
||||
'trace.token.context': 'Context usage',
|
||||
'trace.token.compressedSaved': 'Saved by compression',
|
||||
|
||||
// ===== Trace Step (TraceStep / constants) =====
|
||||
'trace.step.toolCalls': 'Tool calls',
|
||||
'trace.state.INIT': 'Initializing',
|
||||
'trace.state.THINKING': 'Thinking',
|
||||
'trace.state.PARSING': 'Parsing',
|
||||
'trace.state.EXECUTING': 'Executing',
|
||||
'trace.state.OBSERVING': 'Observing',
|
||||
'trace.state.REFLECTING': 'Reflecting',
|
||||
'trace.state.COMPRESSING': 'Compressing',
|
||||
'trace.state.TERMINATED': 'Terminated',
|
||||
|
||||
// ===== Trace Viewer =====
|
||||
'trace.viewer.rounds': '{{count}} round(s)',
|
||||
'trace.viewer.waiting': 'Waiting for agent activity...',
|
||||
'trace.viewer.roundNumber': 'Round {{index}}',
|
||||
'trace.viewer.inProgress': 'In progress',
|
||||
'trace.viewer.completed': 'Completed',
|
||||
'trace.viewer.steps': '{{count}} step(s)',
|
||||
|
||||
// ===== Workspace Viewer =====
|
||||
'workspace.currentWorkspace': 'Current workspace',
|
||||
'workspace.openInFileManager': 'Open in file manager',
|
||||
'workspace.showInFileManager': 'Show in file manager',
|
||||
'workspace.coreFiles': 'Core files ({{count}}/{{total}})',
|
||||
'workspace.emptyFile': '(empty file)',
|
||||
'workspace.fileMissing': 'File does not exist',
|
||||
'workspace.autoDirs': 'Auto directories',
|
||||
'workspace.dirFileCount': '{{count}} files',
|
||||
'workspace.dirMissing': 'Does not exist',
|
||||
'workspace.noData': 'No data',
|
||||
'workspace.loadFailed': 'Failed to load workspace info',
|
||||
'workspace.openFailed': 'Failed to open folder',
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user