octo-agent 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.clacky/skills/commit/SKILL.md +423 -0
- data/.clacky/skills/gem-release/SKILL.md +199 -0
- data/.clacky/skills/gem-release/scripts/release.sh +304 -0
- data/.clacky/skills/oss-upload/SKILL.md +47 -0
- data/.octorules +106 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +76 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/CONTRIBUTING.md +92 -0
- data/Dockerfile +28 -0
- data/LICENSE.txt +22 -0
- data/POSITIONING.md +46 -0
- data/README.md +134 -0
- data/README_CN.md +134 -0
- data/Rakefile +34 -0
- data/benchmark/fixtures/sample_project/Gemfile +3 -0
- data/benchmark/fixtures/sample_project/lib/api_handler.rb +32 -0
- data/benchmark/fixtures/sample_project/lib/order_calculator.rb +23 -0
- data/benchmark/fixtures/sample_project/lib/user_renderer.rb +20 -0
- data/benchmark/fixtures/sample_project/spec/order_calculator_spec.rb +20 -0
- data/benchmark/results/EVALUATION_REPORT.md +165 -0
- data/benchmark/results/baseline_20260511_174424.json +128 -0
- data/benchmark/results/report_20260511_175256.json +271 -0
- data/benchmark/results/report_20260511_175444.json +271 -0
- data/benchmark/results/treatment_20260511_175103.json +130 -0
- data/benchmark/runner.rb +441 -0
- data/bin/octo +7 -0
- data/docs/agent-first-ui-design.md +77 -0
- data/docs/billing-system.md +318 -0
- data/docs/channel-architecture.md +235 -0
- data/docs/engineering-article.md +343 -0
- data/docs/session-skill-invocation.md +69 -0
- data/docs/time_machine_design.md +247 -0
- data/docs/ui2-architecture.md +124 -0
- data/homebrew/README.md +96 -0
- data/homebrew/openocto.rb +24 -0
- data/lib/octo/agent/hook_manager.rb +61 -0
- data/lib/octo/agent/llm_caller.rb +800 -0
- data/lib/octo/agent/memory_updater.rb +246 -0
- data/lib/octo/agent/message_compressor.rb +225 -0
- data/lib/octo/agent/message_compressor_helper.rb +869 -0
- data/lib/octo/agent/next_message_suggester.rb +215 -0
- data/lib/octo/agent/session_serializer.rb +685 -0
- data/lib/octo/agent/skill_auto_creator.rb +114 -0
- data/lib/octo/agent/skill_evolution.rb +61 -0
- data/lib/octo/agent/skill_manager.rb +466 -0
- data/lib/octo/agent/skill_reflector.rb +89 -0
- data/lib/octo/agent/system_prompt_builder.rb +101 -0
- data/lib/octo/agent/time_machine.rb +214 -0
- data/lib/octo/agent/tool_executor.rb +454 -0
- data/lib/octo/agent/tool_registry.rb +150 -0
- data/lib/octo/agent.rb +2180 -0
- data/lib/octo/agent_config.rb +989 -0
- data/lib/octo/agent_profile.rb +112 -0
- data/lib/octo/anthropic_stream_aggregator.rb +137 -0
- data/lib/octo/background_task_registry.rb +324 -0
- data/lib/octo/banner.rb +34 -0
- data/lib/octo/bedrock_stream_aggregator.rb +137 -0
- data/lib/octo/block_font.rb +331 -0
- data/lib/octo/cli.rb +968 -0
- data/lib/octo/client.rb +623 -0
- data/lib/octo/default_agents/SOUL.md +3 -0
- data/lib/octo/default_agents/USER.md +1 -0
- data/lib/octo/default_agents/base_prompt.md +66 -0
- data/lib/octo/default_agents/coding/profile.yml +2 -0
- data/lib/octo/default_agents/coding/system_prompt.md +67 -0
- data/lib/octo/default_agents/general/profile.yml +2 -0
- data/lib/octo/default_agents/general/system_prompt.md +16 -0
- data/lib/octo/default_parsers/doc_parser.rb +69 -0
- data/lib/octo/default_parsers/docx_parser.rb +188 -0
- data/lib/octo/default_parsers/pdf_parser.rb +120 -0
- data/lib/octo/default_parsers/pdf_parser_ocr.py +103 -0
- data/lib/octo/default_parsers/pdf_parser_plumber.py +62 -0
- data/lib/octo/default_parsers/pptx_parser.rb +140 -0
- data/lib/octo/default_parsers/xlsx_parser.rb +121 -0
- data/lib/octo/default_skills/browser-setup/SKILL.md +426 -0
- data/lib/octo/default_skills/channel-manager/SKILL.md +623 -0
- data/lib/octo/default_skills/channel-manager/dingtalk_setup.rb +191 -0
- data/lib/octo/default_skills/channel-manager/discord_setup.rb +199 -0
- data/lib/octo/default_skills/channel-manager/feishu_setup.rb +574 -0
- data/lib/octo/default_skills/channel-manager/import_lark_skills.rb +97 -0
- data/lib/octo/default_skills/channel-manager/install_feishu_skills.rb +105 -0
- data/lib/octo/default_skills/channel-manager/weixin_setup.rb +274 -0
- data/lib/octo/default_skills/code-explorer/SKILL.md +36 -0
- data/lib/octo/default_skills/cron-task-creator/SKILL.md +257 -0
- data/lib/octo/default_skills/cron-task-creator/evals/evals.json +38 -0
- data/lib/octo/default_skills/onboard/SKILL.md +578 -0
- data/lib/octo/default_skills/onboard/scripts/import_external_skills.rb +413 -0
- data/lib/octo/default_skills/onboard/scripts/install_builtin_skills.rb +97 -0
- data/lib/octo/default_skills/persist-memory/SKILL.md +59 -0
- data/lib/octo/default_skills/personal-website/SKILL.md +113 -0
- data/lib/octo/default_skills/personal-website/publish.rb +235 -0
- data/lib/octo/default_skills/product-help/SKILL.md +123 -0
- data/lib/octo/default_skills/product-help/docs/agent-config.md +74 -0
- data/lib/octo/default_skills/product-help/docs/best-practices.md +49 -0
- data/lib/octo/default_skills/product-help/docs/browser-tool.md +53 -0
- data/lib/octo/default_skills/product-help/docs/built-in-skills.md +43 -0
- data/lib/octo/default_skills/product-help/docs/cli-reference.md +82 -0
- data/lib/octo/default_skills/product-help/docs/create-your-first-skill.md +47 -0
- data/lib/octo/default_skills/product-help/docs/faq.md +98 -0
- data/lib/octo/default_skills/product-help/docs/how-to-use-a-skill.md +58 -0
- data/lib/octo/default_skills/product-help/docs/installation.md +59 -0
- data/lib/octo/default_skills/product-help/docs/memory-system.md +61 -0
- data/lib/octo/default_skills/product-help/docs/octorules.md +62 -0
- data/lib/octo/default_skills/product-help/docs/session-management.md +63 -0
- data/lib/octo/default_skills/product-help/docs/skill-basics.md +55 -0
- data/lib/octo/default_skills/product-help/docs/skill-frontmatter.md +61 -0
- data/lib/octo/default_skills/product-help/docs/web-server.md +49 -0
- data/lib/octo/default_skills/product-help/docs/what-is-octo.md +37 -0
- data/lib/octo/default_skills/product-help/docs/windows-installation.md +36 -0
- data/lib/octo/default_skills/product-help/docs/writing-tips.md +53 -0
- data/lib/octo/default_skills/recall-memory/SKILL.md +65 -0
- data/lib/octo/default_skills/skill-add/SKILL.md +59 -0
- data/lib/octo/default_skills/skill-add/scripts/install_from_zip.rb +295 -0
- data/lib/octo/default_skills/skill-creator/SKILL.md +602 -0
- data/lib/octo/default_skills/skill-creator/agents/analyzer.md +274 -0
- data/lib/octo/default_skills/skill-creator/agents/comparator.md +202 -0
- data/lib/octo/default_skills/skill-creator/agents/grader.md +223 -0
- data/lib/octo/default_skills/skill-creator/eval-viewer/generate_review.py +471 -0
- data/lib/octo/default_skills/skill-creator/eval-viewer/viewer.html +1325 -0
- data/lib/octo/default_skills/skill-creator/references/schemas.md +430 -0
- data/lib/octo/default_skills/skill-creator/scripts/__init__.py +0 -0
- data/lib/octo/default_skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- data/lib/octo/default_skills/skill-creator/scripts/generate_report.py +326 -0
- data/lib/octo/default_skills/skill-creator/scripts/improve_description.py +310 -0
- data/lib/octo/default_skills/skill-creator/scripts/quick_validate.py +103 -0
- data/lib/octo/default_skills/skill-creator/scripts/run_eval.py +317 -0
- data/lib/octo/default_skills/skill-creator/scripts/run_loop.py +331 -0
- data/lib/octo/default_skills/skill-creator/scripts/utils.py +47 -0
- data/lib/octo/default_skills/skill-creator/scripts/validate_skill_frontmatter.rb +143 -0
- data/lib/octo/idle_compression_timer.rb +115 -0
- data/lib/octo/json_ui_controller.rb +204 -0
- data/lib/octo/message_format/anthropic.rb +409 -0
- data/lib/octo/message_format/bedrock.rb +361 -0
- data/lib/octo/message_format/open_ai.rb +222 -0
- data/lib/octo/message_history.rb +373 -0
- data/lib/octo/openai_stream_aggregator.rb +130 -0
- data/lib/octo/plain_ui_controller.rb +166 -0
- data/lib/octo/providers.rb +534 -0
- data/lib/octo/server/browser_manager.rb +397 -0
- data/lib/octo/server/channel/adapters/base.rb +82 -0
- data/lib/octo/server/channel/adapters/dingtalk/adapter.rb +314 -0
- data/lib/octo/server/channel/adapters/dingtalk/api_client.rb +391 -0
- data/lib/octo/server/channel/adapters/dingtalk/stream_client.rb +203 -0
- data/lib/octo/server/channel/adapters/discord/adapter.rb +229 -0
- data/lib/octo/server/channel/adapters/discord/api_client.rb +107 -0
- data/lib/octo/server/channel/adapters/discord/gateway_client.rb +270 -0
- data/lib/octo/server/channel/adapters/feishu/adapter.rb +320 -0
- data/lib/octo/server/channel/adapters/feishu/bot.rb +478 -0
- data/lib/octo/server/channel/adapters/feishu/file_processor.rb +36 -0
- data/lib/octo/server/channel/adapters/feishu/message_parser.rb +129 -0
- data/lib/octo/server/channel/adapters/feishu/ws_client.rb +423 -0
- data/lib/octo/server/channel/adapters/telegram/adapter.rb +375 -0
- data/lib/octo/server/channel/adapters/telegram/api_client.rb +205 -0
- data/lib/octo/server/channel/adapters/wecom/adapter.rb +148 -0
- data/lib/octo/server/channel/adapters/wecom/media_downloader.rb +115 -0
- data/lib/octo/server/channel/adapters/wecom/ws_client.rb +395 -0
- data/lib/octo/server/channel/adapters/weixin/adapter.rb +692 -0
- data/lib/octo/server/channel/adapters/weixin/api_client.rb +402 -0
- data/lib/octo/server/channel/channel_config.rb +178 -0
- data/lib/octo/server/channel/channel_manager.rb +468 -0
- data/lib/octo/server/channel/channel_ui_controller.rb +224 -0
- data/lib/octo/server/channel.rb +33 -0
- data/lib/octo/server/discover.rb +77 -0
- data/lib/octo/server/epipe_safe_io.rb +105 -0
- data/lib/octo/server/http_server.rb +3554 -0
- data/lib/octo/server/scheduler.rb +317 -0
- data/lib/octo/server/server_master.rb +325 -0
- data/lib/octo/server/session_registry.rb +431 -0
- data/lib/octo/server/web_ui_controller.rb +487 -0
- data/lib/octo/session_manager.rb +385 -0
- data/lib/octo/skill.rb +466 -0
- data/lib/octo/skill_loader.rb +328 -0
- data/lib/octo/tools/base.rb +118 -0
- data/lib/octo/tools/browser.rb +625 -0
- data/lib/octo/tools/edit.rb +165 -0
- data/lib/octo/tools/file_reader.rb +549 -0
- data/lib/octo/tools/glob.rb +162 -0
- data/lib/octo/tools/grep.rb +356 -0
- data/lib/octo/tools/invoke_skill.rb +96 -0
- data/lib/octo/tools/list_tasks.rb +54 -0
- data/lib/octo/tools/redo_task.rb +41 -0
- data/lib/octo/tools/request_user_feedback.rb +84 -0
- data/lib/octo/tools/security.rb +333 -0
- data/lib/octo/tools/terminal/output_cleaner.rb +63 -0
- data/lib/octo/tools/terminal/persistent_session.rb +268 -0
- data/lib/octo/tools/terminal/safe_rm.sh +106 -0
- data/lib/octo/tools/terminal/session_manager.rb +213 -0
- data/lib/octo/tools/terminal.rb +1828 -0
- data/lib/octo/tools/todo_manager.rb +374 -0
- data/lib/octo/tools/trash_manager.rb +388 -0
- data/lib/octo/tools/undo_task.rb +35 -0
- data/lib/octo/tools/web_fetch.rb +242 -0
- data/lib/octo/tools/web_search.rb +260 -0
- data/lib/octo/tools/write.rb +77 -0
- data/lib/octo/ui2/block_font.rb +10 -0
- data/lib/octo/ui2/components/base_component.rb +163 -0
- data/lib/octo/ui2/components/command_suggestions.rb +290 -0
- data/lib/octo/ui2/components/common_component.rb +96 -0
- data/lib/octo/ui2/components/inline_input.rb +226 -0
- data/lib/octo/ui2/components/input_area.rb +1338 -0
- data/lib/octo/ui2/components/message_component.rb +99 -0
- data/lib/octo/ui2/components/modal_component.rb +419 -0
- data/lib/octo/ui2/components/todo_area.rb +149 -0
- data/lib/octo/ui2/components/tool_component.rb +107 -0
- data/lib/octo/ui2/components/welcome_banner.rb +139 -0
- data/lib/octo/ui2/layout_manager.rb +807 -0
- data/lib/octo/ui2/line_editor.rb +363 -0
- data/lib/octo/ui2/markdown_renderer.rb +100 -0
- data/lib/octo/ui2/output_buffer.rb +370 -0
- data/lib/octo/ui2/progress_handle.rb +362 -0
- data/lib/octo/ui2/progress_indicator.rb +55 -0
- data/lib/octo/ui2/screen_buffer.rb +273 -0
- data/lib/octo/ui2/terminal_detector.rb +119 -0
- data/lib/octo/ui2/theme_manager.rb +85 -0
- data/lib/octo/ui2/themes/base_theme.rb +105 -0
- data/lib/octo/ui2/themes/hacker_theme.rb +62 -0
- data/lib/octo/ui2/themes/minimal_theme.rb +56 -0
- data/lib/octo/ui2/thinking_verbs.rb +26 -0
- data/lib/octo/ui2/ui_controller.rb +1625 -0
- data/lib/octo/ui2/view_renderer.rb +177 -0
- data/lib/octo/ui2.rb +40 -0
- data/lib/octo/ui_interface.rb +154 -0
- data/lib/octo/utils/arguments_parser.rb +191 -0
- data/lib/octo/utils/browser_detector.rb +195 -0
- data/lib/octo/utils/encoding.rb +92 -0
- data/lib/octo/utils/environment_detector.rb +140 -0
- data/lib/octo/utils/file_ignore_helper.rb +170 -0
- data/lib/octo/utils/file_processor.rb +601 -0
- data/lib/octo/utils/gitignore_parser.rb +154 -0
- data/lib/octo/utils/limit_stack.rb +152 -0
- data/lib/octo/utils/logger.rb +124 -0
- data/lib/octo/utils/login_shell.rb +72 -0
- data/lib/octo/utils/model_pricing.rb +646 -0
- data/lib/octo/utils/parser_manager.rb +165 -0
- data/lib/octo/utils/path_helper.rb +15 -0
- data/lib/octo/utils/scripts_manager.rb +59 -0
- data/lib/octo/utils/string_matcher.rb +158 -0
- data/lib/octo/utils/trash_directory.rb +112 -0
- data/lib/octo/utils/workspace_rules.rb +46 -0
- data/lib/octo/version.rb +5 -0
- data/lib/octo/web/app.css +7141 -0
- data/lib/octo/web/app.js +543 -0
- data/lib/octo/web/apple-touch-icon.png +0 -0
- data/lib/octo/web/auth.js +150 -0
- data/lib/octo/web/channels.js +276 -0
- data/lib/octo/web/datepicker.js +205 -0
- data/lib/octo/web/favicon.png +0 -0
- data/lib/octo/web/i18n.js +1073 -0
- data/lib/octo/web/icon-512.png +0 -0
- data/lib/octo/web/icon-dark.svg +25 -0
- data/lib/octo/web/icon.svg +29 -0
- data/lib/octo/web/index.html +871 -0
- data/lib/octo/web/marked.min.js +69 -0
- data/lib/octo/web/onboard.js +491 -0
- data/lib/octo/web/profile.js +442 -0
- data/lib/octo/web/sessions.js +4421 -0
- data/lib/octo/web/settings.js +913 -0
- data/lib/octo/web/sidebar.js +32 -0
- data/lib/octo/web/skills.js +885 -0
- data/lib/octo/web/tasks.js +297 -0
- data/lib/octo/web/theme.js +105 -0
- data/lib/octo/web/trash.js +343 -0
- data/lib/octo/web/vendor/hljs/highlight.min.js +1244 -0
- data/lib/octo/web/vendor/hljs/hljs-theme.css +95 -0
- data/lib/octo/web/vendor/katex/auto-render.min.js +1 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/katex.min.css +1 -0
- data/lib/octo/web/vendor/katex/katex.min.js +1 -0
- data/lib/octo/web/version.js +449 -0
- data/lib/octo/web/weixin-qr.html +209 -0
- data/lib/octo/web/ws-dispatcher.js +357 -0
- data/lib/octo/web/ws.js +128 -0
- data/lib/octo.rb +145 -0
- data/scripts/build/build.sh +329 -0
- data/scripts/build/lib/apt.sh +56 -0
- data/scripts/build/lib/brew.sh +89 -0
- data/scripts/build/lib/colors.sh +17 -0
- data/scripts/build/lib/gem.sh +95 -0
- data/scripts/build/lib/mise.sh +125 -0
- data/scripts/build/lib/network.sh +157 -0
- data/scripts/build/lib/os.sh +57 -0
- data/scripts/build/lib/shell.sh +37 -0
- data/scripts/build/src/install.sh.cc +174 -0
- data/scripts/build/src/install_browser.sh.cc +101 -0
- data/scripts/build/src/install_full.sh.cc +290 -0
- data/scripts/build/src/install_rails_deps.sh.cc +145 -0
- data/scripts/build/src/install_system_deps.sh.cc +123 -0
- data/scripts/build/src/uninstall.sh.cc +101 -0
- data/scripts/install.ps1 +532 -0
- data/scripts/install.sh +567 -0
- data/scripts/install_browser.sh +479 -0
- data/scripts/install_full.sh +838 -0
- data/scripts/install_rails_deps.sh +746 -0
- data/scripts/install_system_deps.sh +518 -0
- data/scripts/uninstall.sh +287 -0
- data/sig/octo.rbs +4 -0
- metadata +614 -0
|
@@ -0,0 +1,1073 @@
|
|
|
1
|
+
// i18n.js — Lightweight internationalization module
|
|
2
|
+
// Supports English (en) and Chinese (zh).
|
|
3
|
+
// Language is persisted in localStorage under the key "octo-lang".
|
|
4
|
+
// Usage:
|
|
5
|
+
// I18n.t("key") → translated string
|
|
6
|
+
// I18n.t("key", {name:"X"})→ translated string with {{name}} replaced
|
|
7
|
+
// I18n.applyAll() → apply data-i18n / data-i18n-placeholder to DOM
|
|
8
|
+
|
|
9
|
+
const I18n = (() => {
|
|
10
|
+
const STORAGE_KEY = "octo-lang";
|
|
11
|
+
const DEFAULT_LANG = "en";
|
|
12
|
+
|
|
13
|
+
// ── Translation dictionary ─────────────────────────────────────────────────
|
|
14
|
+
const TRANSLATIONS = {
|
|
15
|
+
en: {
|
|
16
|
+
// ── Sidebar ──
|
|
17
|
+
"sidebar.chat": "Chat",
|
|
18
|
+
"sidebar.config": "Config",
|
|
19
|
+
"sidebar.tasks": "Task Management",
|
|
20
|
+
"sidebar.skills": "Skill Management",
|
|
21
|
+
"sidebar.channels": "Channel Management",
|
|
22
|
+
"sidebar.trash": "File Recall",
|
|
23
|
+
"sidebar.profile": "Assistant Memory",
|
|
24
|
+
"sidebar.memories": "Memories",
|
|
25
|
+
"sidebar.dataSection": "My Data",
|
|
26
|
+
"sidebar.settings": "Settings",
|
|
27
|
+
|
|
28
|
+
// ── Welcome screen ──
|
|
29
|
+
"welcome.title": "Welcome to {{brand}}",
|
|
30
|
+
"welcome.body": "Create a new session or select one from the sidebar.",
|
|
31
|
+
"welcome.btn": "New Session",
|
|
32
|
+
|
|
33
|
+
// ── Chat panel ──
|
|
34
|
+
"chat.status.idle": "idle",
|
|
35
|
+
"chat.status.running": "running",
|
|
36
|
+
"chat.status.error": "error",
|
|
37
|
+
// ── Background tasks (fire-and-forget) ──
|
|
38
|
+
"bgtasks.badge": "🔄 {{n}} background task(s)",
|
|
39
|
+
"bgtasks.tooltip": "Hover for details · click to expand",
|
|
40
|
+
"bgtasks.notice": "Background task {{status}}:",
|
|
41
|
+
// ── Inbox queue hint (above the input bar) ──
|
|
42
|
+
"inbox.queue.one": "1 message waiting — the agent will read it next.",
|
|
43
|
+
"inbox.queue.many": "{{n}} messages waiting — the agent will read them next.",
|
|
44
|
+
"chat.input.placeholder": "Message… (Enter to send, Shift+Enter for newline)",
|
|
45
|
+
"chat.input.placeholderRunning": "AI is working — you can still send extra info anytime...",
|
|
46
|
+
"chat.input.placeholderMobile": "Message…",
|
|
47
|
+
"chat.input.placeholderRunningMobile": "Add more info…",
|
|
48
|
+
"chat.btn.send": "Send",
|
|
49
|
+
"chat.thinking": "Thinking…",
|
|
50
|
+
"chat.retrying": "Retrying",
|
|
51
|
+
"chat.history_load_failed": "Could not load history",
|
|
52
|
+
"chat.history_start": "No more history",
|
|
53
|
+
"chat.image_expired": "Expired",
|
|
54
|
+
"chat.done": "Done — {{n}} iteration(s)",
|
|
55
|
+
"chat.done.duration": " · {{duration}}s",
|
|
56
|
+
"chat.done.cache": "Cache hit {{rate}}% ({{hits}}/{{total}}) · {{tokens}} tokens reused",
|
|
57
|
+
"chat.interrupted": "Interrupted.",
|
|
58
|
+
"chat.feedback_hint": "Or type your own answer below ↓",
|
|
59
|
+
"chat.newMessageHint": "New messages ↓",
|
|
60
|
+
"chat.retry": "Retry",
|
|
61
|
+
"chat.resetSession": "Reset session",
|
|
62
|
+
"chat.resetSessionConfirm": "Reset will start a brand-new session. The current conversation history stays in your sidebar but will no longer be active. Continue?",
|
|
63
|
+
"chat.copy": "Copy",
|
|
64
|
+
"chat.copied": "Copied",
|
|
65
|
+
"chat.empty.title": "Start the conversation",
|
|
66
|
+
"chat.empty.subtitle": "Ask anything, or use a skill to get going.",
|
|
67
|
+
"chat.empty.tip1": "Type / to browse skills",
|
|
68
|
+
"chat.empty.tip2": "Attach images, PDFs, or docs for context",
|
|
69
|
+
"chat.empty.tip3": "Shift+Enter for a new line",
|
|
70
|
+
"chat.empty.tip4": "Each session is isolated, but long-term memories are shared across sessions",
|
|
71
|
+
|
|
72
|
+
// ── Session list ──
|
|
73
|
+
"sessions.empty": "No sessions yet",
|
|
74
|
+
"sessions.confirmDelete": "Delete session {{name}}? This cannot be undone.",
|
|
75
|
+
"sessions.meta": "{{tasks}} tasks",
|
|
76
|
+
"sessions.metaTasks": "{{n}} tasks",
|
|
77
|
+
"sessions.deleteTitle": "Delete session",
|
|
78
|
+
"sessions.createError": "Error: ",
|
|
79
|
+
"sessions.dirNotEmpty": "Directory already exists and is not empty.",
|
|
80
|
+
"sessions.export.tooltip": "Download session files (session.json + chunks + today's log) for debugging",
|
|
81
|
+
"sessions.export.failed": "Failed to download session",
|
|
82
|
+
"sessions.actions.tooltip": "Click for session actions",
|
|
83
|
+
"sessions.actions.download": "Download session files",
|
|
84
|
+
"sessions.actions.downloadHint": "for debugging",
|
|
85
|
+
"sib.dir.tooltip": "Click to change directory",
|
|
86
|
+
"sib.dir.changePrompt": "Change working directory:",
|
|
87
|
+
"sib.model.tooltip": "Click to switch model",
|
|
88
|
+
"sib.signal.tooltip": "Recent LLM latency",
|
|
89
|
+
"sib.reasoning.tooltip": "Click to change reasoning effort",
|
|
90
|
+
"sib.reasoning.label": "Reasoning",
|
|
91
|
+
"sib.reasoning.heading": "Reasoning effort",
|
|
92
|
+
"sib.reasoning.hint": "Higher effort = deeper thinking, slower response.",
|
|
93
|
+
"sib.reasoning.off": "Default",
|
|
94
|
+
"sib.reasoning.low": "Low",
|
|
95
|
+
"sib.reasoning.medium": "Medium",
|
|
96
|
+
"sib.reasoning.high": "High",
|
|
97
|
+
"sessions.thinking": "Thinking…",
|
|
98
|
+
"sessions.default_name": "Session {{n}}",
|
|
99
|
+
"sessions.cronGroup": "Scheduled Tasks",
|
|
100
|
+
"sessions.cronGroupMeta": "{{n}} sessions",
|
|
101
|
+
"sessions.cronLoading": "Loading scheduled tasks...",
|
|
102
|
+
"sessions.badge.cron": "Auto",
|
|
103
|
+
"sessions.badge.channel": "Channel",
|
|
104
|
+
"sessions.badge.coding": "Coding",
|
|
105
|
+
"sessions.badge.setup": "Setup",
|
|
106
|
+
"sessions.newSession": "+ New Session",
|
|
107
|
+
"sessions.actions.pin": "Pin",
|
|
108
|
+
"sessions.actions.unpin": "Unpin",
|
|
109
|
+
"sessions.actions.rename": "Rename",
|
|
110
|
+
"sessions.actions.delete": "Delete",
|
|
111
|
+
"sessions.newSessionAdvanced": "More Options",
|
|
112
|
+
"sessions.loadMore": "Load more sessions",
|
|
113
|
+
"sessions.loadingMore": "Loading…",
|
|
114
|
+
"sessions.search.placeholder": "Search sessions…",
|
|
115
|
+
"sessions.search.typeAll": "All types",
|
|
116
|
+
"sessions.search.typeManual": "Default",
|
|
117
|
+
"sessions.search.typeCron": "Scheduled",
|
|
118
|
+
"sessions.search.typeChannel": "Channel",
|
|
119
|
+
"sessions.search.typeCoding": "Coding",
|
|
120
|
+
"sessions.search.typeSetup": "Setup",
|
|
121
|
+
"sessions.search.datePlaceholder": "Date",
|
|
122
|
+
|
|
123
|
+
// ── Modal ──
|
|
124
|
+
"modal.yes": "Yes",
|
|
125
|
+
"modal.no": "No",
|
|
126
|
+
"modal.ok": "OK",
|
|
127
|
+
"modal.cancel": "Cancel",
|
|
128
|
+
|
|
129
|
+
// ── Auth ──
|
|
130
|
+
"auth.accessKeyRequired": "Access key required:",
|
|
131
|
+
"auth.rateLimited": "Too many failed attempts. Please try again in {{seconds}} seconds.",
|
|
132
|
+
|
|
133
|
+
// ── New Session Modal ──
|
|
134
|
+
"sessions.modal.title": "Create New Session",
|
|
135
|
+
"sessions.modal.agent": "Agent",
|
|
136
|
+
"sessions.modal.agent.general": "General",
|
|
137
|
+
"sessions.modal.agent.coding": "Coding",
|
|
138
|
+
"sessions.modal.name": "Session Name",
|
|
139
|
+
"sessions.modal.name.placeholder": "Leave empty to auto-generate",
|
|
140
|
+
"sessions.modal.model": "Model",
|
|
141
|
+
"sessions.modal.directory": "Working Directory",
|
|
142
|
+
"sessions.modal.directory.placeholder": "~/octo_workspace",
|
|
143
|
+
"sessions.modal.initProject": "Initialize full-stack project (/new)",
|
|
144
|
+
"sessions.modal.create": "Create Session",
|
|
145
|
+
|
|
146
|
+
// ── Offline banner ──
|
|
147
|
+
"offline.banner": "Server disconnected — reconnecting…",
|
|
148
|
+
"chat.disconnected.hint": "Server disconnected. Please wait for reconnection.",
|
|
149
|
+
|
|
150
|
+
// ── Version / Upgrade ──
|
|
151
|
+
"upgrade.desc": "A new version is available. It will install in the background — you can keep using the app.",
|
|
152
|
+
"upgrade.btn.upgrade": "Upgrade Now",
|
|
153
|
+
"upgrade.btn.cancel": "Cancel",
|
|
154
|
+
"upgrade.btn.restart": "↻ Restart Now",
|
|
155
|
+
"upgrade.installing": "Installing…",
|
|
156
|
+
"upgrade.done": "Upgrade complete!",
|
|
157
|
+
"upgrade.failed": "Upgrade failed. Try again or run manually: gem update octo",
|
|
158
|
+
"upgrade.reconnecting": "Restarting server…",
|
|
159
|
+
"upgrade.restart.success": "✓ Restarted successfully!",
|
|
160
|
+
"upgrade.restart.timeout.title": "Hot restart didn't complete",
|
|
161
|
+
"upgrade.restart.timeout.desc": "The server didn't come back within 30 s. Please recover using one of the methods below:",
|
|
162
|
+
"upgrade.restart.timeout.tray": "From the tray menu, choose “Quit” and start the app again.",
|
|
163
|
+
"upgrade.restart.timeout.cli": "If you launched from a terminal, run: {{cmd}}",
|
|
164
|
+
"upgrade.restart.timeout.retry": "Try Again",
|
|
165
|
+
"upgrade.tooltip.upgrading": "Upgrading — click to see progress",
|
|
166
|
+
"upgrade.tooltip.new": "v{{latest}} available — click to upgrade",
|
|
167
|
+
"upgrade.tooltip.ok": "v{{current}} (up to date)",
|
|
168
|
+
"upgrade.tooltip.needs_restart": "Upgrade complete — click to restart",
|
|
169
|
+
"upgrade.tooltip.done": "Restarted successfully",
|
|
170
|
+
|
|
171
|
+
// ── Tasks panel ──
|
|
172
|
+
"tasks.title": "Scheduled Tasks",
|
|
173
|
+
"tasks.subtitle": "Manage and schedule automated tasks for your assistant",
|
|
174
|
+
"tasks.btn.create": "Create Task",
|
|
175
|
+
"tasks.btn.createTask": "Create Task",
|
|
176
|
+
"tasks.empty": "(empty)",
|
|
177
|
+
"tasks.noScheduled": "No scheduled tasks.",
|
|
178
|
+
"tasks.noTasks": "No tasks",
|
|
179
|
+
"tasks.count": "{{n}} task(s)",
|
|
180
|
+
"tasks.manual": "Manual",
|
|
181
|
+
"tasks.col.name": "Name",
|
|
182
|
+
"tasks.col.schedule": "Schedule",
|
|
183
|
+
"tasks.col.task": "Task",
|
|
184
|
+
"tasks.btn.run": "Run",
|
|
185
|
+
"tasks.btn.edit": "Edit",
|
|
186
|
+
"tasks.btn.pause": "Pause",
|
|
187
|
+
"tasks.btn.resume": "Resume",
|
|
188
|
+
"tasks.paused": "Paused",
|
|
189
|
+
"tasks.toggleError": "Error updating task.",
|
|
190
|
+
"tasks.runError": "Error: ",
|
|
191
|
+
"tasks.sessionError": "Error creating session: ",
|
|
192
|
+
"tasks.confirmDelete": "Delete task \"{{name}}\"?",
|
|
193
|
+
"tasks.deleteError": "Error deleting task.",
|
|
194
|
+
"tasks.label.active": "Tasks",
|
|
195
|
+
"tasks.label.none": "No tasks",
|
|
196
|
+
|
|
197
|
+
// ── Skills panel ──
|
|
198
|
+
"skills.title": "Skills",
|
|
199
|
+
"skills.subtitle": "Extend your assistant's capabilities with custom skills",
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
// ── Creator trash ──
|
|
210
|
+
"trash.title": "File Recall",
|
|
211
|
+
"trash.subtitle": "Files the agent moved to trash across all projects. Recall them back to where they were, or clear the ones you don't need.",
|
|
212
|
+
"trash.refresh": "Refresh",
|
|
213
|
+
"trash.emptyOld": "Empty >7 days",
|
|
214
|
+
"trash.emptyOrphans":"Clean orphans",
|
|
215
|
+
"trash.emptyAll": "Empty all",
|
|
216
|
+
"trash.empty": "Nothing in the trash.",
|
|
217
|
+
"trash.loading": "Loading trash…",
|
|
218
|
+
"trash.summary": "{{count}} file(s), {{size}}",
|
|
219
|
+
"trash.summaryOrphans": "{{count}} orphan(s)",
|
|
220
|
+
"trash.orphan": "orphan",
|
|
221
|
+
"trash.orphanHint": "Original project directory no longer exists (likely a test temp dir). Safe to permanently delete.",
|
|
222
|
+
"trash.noOrphans": "No orphan trash entries detected.",
|
|
223
|
+
"trash.project": "Project",
|
|
224
|
+
"trash.deletedAt": "Deleted",
|
|
225
|
+
"trash.restore": "Restore",
|
|
226
|
+
"trash.delete": "Delete",
|
|
227
|
+
"trash.restoreOk": "Restored: {{path}}",
|
|
228
|
+
"trash.restoreFail": "Restore failed: {{msg}}",
|
|
229
|
+
"trash.confirmDeleteOne": "Permanently delete \"{{name}}\"?\nThis cannot be undone.",
|
|
230
|
+
"trash.confirmEmptyOld": "Permanently delete all trashed files older than 7 days?\nThis cannot be undone.",
|
|
231
|
+
"trash.confirmEmptyAll": "Permanently delete ALL trashed files across every project?\nThis cannot be undone.",
|
|
232
|
+
"trash.confirmEmptyOrphans": "Permanently delete {{count}} orphan trash entries whose original project directory is gone?\nThis cannot be undone.",
|
|
233
|
+
"trash.emptied": "Permanently deleted {{count}} file(s), freed {{size}}.",
|
|
234
|
+
"trash.orphansCleaned": "Cleaned {{count}} orphan entries, freed {{size}}. ({{failed}} failed)",
|
|
235
|
+
"trash.nothingOld": "No files older than 7 days.",
|
|
236
|
+
|
|
237
|
+
// ── Profile (unified read-only view of USER.md / SOUL.md / memories) ──
|
|
238
|
+
"profile.title": "Assistant Memory",
|
|
239
|
+
"profile.subtitle": "A window into the assistant's inner life: who it is, who you are, and what it remembers about your work together.",
|
|
240
|
+
"profile.whoIAm": "Who I am",
|
|
241
|
+
"profile.whoYouAre": "Who you are",
|
|
242
|
+
"profile.statusDefault": "Using built-in default",
|
|
243
|
+
"profile.statusCustom": "Custom override active",
|
|
244
|
+
"profile.loadFail": "Failed to load",
|
|
245
|
+
"profile.emptyContent": "(empty)",
|
|
246
|
+
|
|
247
|
+
// Profile tabs
|
|
248
|
+
"profile.tab.soul": "Soul",
|
|
249
|
+
"profile.tab.user": "User",
|
|
250
|
+
"profile.tab.memories": "Memories",
|
|
251
|
+
|
|
252
|
+
// Per-tab curate actions
|
|
253
|
+
"profile.soul.curateHint": "Not quite right? Let the assistant curate this through a short conversation.",
|
|
254
|
+
"profile.soul.curateBtn": "Have the assistant curate this",
|
|
255
|
+
"profile.user.curateHint": "Changed jobs? Picked up new interests? Let the assistant update your profile.",
|
|
256
|
+
"profile.user.curateBtn": "Have the assistant update this",
|
|
257
|
+
"profile.curateFail": "Could not start the curation session",
|
|
258
|
+
"profile.curateName.soul": "Curate soul",
|
|
259
|
+
"profile.curateName.user": "Curate profile",
|
|
260
|
+
|
|
261
|
+
// Legacy update keys — retained for backward compat, no longer used by UI.
|
|
262
|
+
"profile.update": "Update profile",
|
|
263
|
+
"profile.updateFail": "Could not start the update session",
|
|
264
|
+
// Legacy editor keys (still referenced by old tests / translations).
|
|
265
|
+
"profile.user.placeholder": "Tell the assistant about yourself — name, role, preferences, working style…",
|
|
266
|
+
"profile.soul.placeholder": "Describe the assistant's personality — tone, values, communication style…",
|
|
267
|
+
"profile.save": "Save",
|
|
268
|
+
"profile.reset": "Reset to default",
|
|
269
|
+
"profile.savedOk": "Saved ✓",
|
|
270
|
+
"profile.resetOk": "Reset to default ✓",
|
|
271
|
+
"profile.saveFail": "Save failed",
|
|
272
|
+
"profile.confirmReset": "Clear your custom override and fall back to the built-in default?",
|
|
273
|
+
|
|
274
|
+
// ── Memories (shown inside Profile panel) ──
|
|
275
|
+
"memories.title": "Memories",
|
|
276
|
+
"memories.subtitle": "Long-term memories stored under ~/.octo/memories/. Most recent first. Use \"Curate\" to let the assistant tidy a memory, or \"Delete\" to drop one.",
|
|
277
|
+
"memories.curate": "Curate",
|
|
278
|
+
"memories.curateTitle": "Open a session and let the assistant tidy this memory with you",
|
|
279
|
+
"memories.curateFail": "Could not start a memory session",
|
|
280
|
+
"memories.curateName": "Curate memory",
|
|
281
|
+
"memories.delete": "Delete",
|
|
282
|
+
"memories.deleteTitle": "Delete this memory",
|
|
283
|
+
"memories.deleteFail": "Delete failed",
|
|
284
|
+
"memories.confirmDelete": "Delete memory \"{{name}}\"?\nIt will be moved to File Recall and can still be recovered from there.",
|
|
285
|
+
"memories.expandTitle": "Show full content",
|
|
286
|
+
"memories.reloadList": "↻ Reload",
|
|
287
|
+
"memories.loading": "Loading…",
|
|
288
|
+
"memories.empty": "No memories yet. The assistant will create them as you work.",
|
|
289
|
+
"memories.emptyHint": "",
|
|
290
|
+
"memories.summary": "{{count}} memory file(s)",
|
|
291
|
+
// Legacy keys — kept for compatibility with any external callers.
|
|
292
|
+
"memories.refresh": "Curate",
|
|
293
|
+
"memories.refreshTitle": "Open a session and let the assistant tidy this memory with you",
|
|
294
|
+
"memories.refreshFail": "Could not start a memory session",
|
|
295
|
+
"memories.new": "+ New Memory",
|
|
296
|
+
"memories.edit": "Edit",
|
|
297
|
+
"memories.save": "Save",
|
|
298
|
+
"memories.cancel": "Cancel",
|
|
299
|
+
"memories.filenamePh": "topic-name.md",
|
|
300
|
+
"memories.contentPh": "Markdown content with optional YAML frontmatter…",
|
|
301
|
+
"memories.filenameRequired": "Filename is required (e.g. topic-name.md).",
|
|
302
|
+
|
|
303
|
+
"skills.btn.new": "New Skill",
|
|
304
|
+
"skills.btn.create": "Create",
|
|
305
|
+
"skills.btn.import": "Import",
|
|
306
|
+
"skills.import.placeholder": "Paste ZIP or GitHub URL…",
|
|
307
|
+
"skills.import.install": "Install",
|
|
308
|
+
"skills.tab.my": "My Skills",
|
|
309
|
+
"skills.empty": "No skills loaded.",
|
|
310
|
+
"skills.empty.createBtn": "Create a new skill with /skill-creator",
|
|
311
|
+
"skills.noSkills": "No skills",
|
|
312
|
+
"skills.count": "{{n}} skill(s)",
|
|
313
|
+
"skills.loading": "Loading…",
|
|
314
|
+
"skills.badge.system": "System",
|
|
315
|
+
"skills.badge.custom": "Custom",
|
|
316
|
+
"skills.badge.invalid": "Invalid",
|
|
317
|
+
"skills.btn.use": "Use",
|
|
318
|
+
"skills.filter.showSystem": "Show system skills",
|
|
319
|
+
"skills.filter.showSystemShort": "Show System",
|
|
320
|
+
"skills.systemDisabledTip": "System skills cannot be disabled",
|
|
321
|
+
"skills.invalid.reason": "This skill has an invalid configuration and cannot be used.",
|
|
322
|
+
"skills.invalid.toggleTip": "Invalid skills cannot be enabled",
|
|
323
|
+
"skills.warning.tooltip": "This skill has a configuration issue but is still usable.\nReason: {{reason}}",
|
|
324
|
+
"skills.toggle.disable": "Disable skill",
|
|
325
|
+
"skills.toggle.enable": "Enable skill",
|
|
326
|
+
"skills.toggle.disableDesc": "AI can auto-invoke. Disable to prevent auto-triggering (manual use still available)",
|
|
327
|
+
"skills.toggle.enableDesc": "AI cannot auto-invoke. Enable to allow auto-triggering",
|
|
328
|
+
"skills.toggleError": "Error: ",
|
|
329
|
+
"skills.ac.empty": "No skills available",
|
|
330
|
+
"skills.upload.uploading": "Uploading…",
|
|
331
|
+
"skills.upload.uploaded": "Uploaded",
|
|
332
|
+
"skills.upload.upload": "Upload",
|
|
333
|
+
"skills.upload.failed": "Failed",
|
|
334
|
+
"skills.upload.publishTip": "Publish to cloud",
|
|
335
|
+
"skills.btn.refresh": "Refresh",
|
|
336
|
+
|
|
337
|
+
// ── Channels panel ──
|
|
338
|
+
"channels.title": "Channels",
|
|
339
|
+
"channels.subtitle": "Connect IM platforms so your users can chat with the assistant via Feishu, WeCom, Weixin, Discord, Telegram or DingTalk",
|
|
340
|
+
"channels.loading": "Loading…",
|
|
341
|
+
"channels.badge.running": "Running",
|
|
342
|
+
"channels.badge.enabled": "Enabled",
|
|
343
|
+
"channels.badge.disabled": "Disabled",
|
|
344
|
+
"channels.badge.notConfigured": "Not configured",
|
|
345
|
+
"channels.hint.running": "Adapter is running and accepting messages from users",
|
|
346
|
+
"channels.hint.enabled": "⚠ Enabled but not running — the adapter may have failed to connect. Run Diagnostics to investigate.",
|
|
347
|
+
"channels.hint.enabledNotRunning":"Enabled but not running — the adapter may have failed to connect. Run Diagnostics to investigate.",
|
|
348
|
+
"channels.hint.idle": "Not configured yet. Click \"Set Up with Agent\" to get started.",
|
|
349
|
+
"channels.hint.notConfigured": "Not configured yet. Click \"Set Up with Agent\" to get started.",
|
|
350
|
+
"channels.hint.disabled": "Configured but turned off. Use the toggle to enable.",
|
|
351
|
+
"channels.toggle.on": "Enabled — click to turn off",
|
|
352
|
+
"channels.toggle.off": "Disabled — click to turn on",
|
|
353
|
+
"channels.btn.test": "Diagnostics",
|
|
354
|
+
"channels.btn.setup": "Set Up with Agent",
|
|
355
|
+
"channels.btn.reconfig": "Reconfigure",
|
|
356
|
+
"channels.btn.reconfigure": "Reconfigure",
|
|
357
|
+
"channels.loadError": "Failed to load channels: {{msg}}",
|
|
358
|
+
"channels.sessionError": "unknown",
|
|
359
|
+
"channels.noSession": "No session returned",
|
|
360
|
+
"channels.feishu.desc": "Connect via Feishu open platform WebSocket long connection",
|
|
361
|
+
"channels.wecom.desc": "Connect via WeCom intelligent robot WebSocket",
|
|
362
|
+
"channels.weixin.desc": "Connect via WeChat iLink bot (QR login, HTTP long-poll)",
|
|
363
|
+
"channels.discord.desc": "Connect via Discord bot, invite via OAuth2 authorization link",
|
|
364
|
+
"channels.telegram.desc": "Connect via Telegram Bot API (HTTPS long-poll, token from @BotFather)",
|
|
365
|
+
"channels.dingtalk.desc": "Connect via DingTalk Stream Mode WebSocket",
|
|
366
|
+
|
|
367
|
+
// ── Settings panel ──
|
|
368
|
+
"settings.title": "Settings",
|
|
369
|
+
"settings.models.title": "AI Models",
|
|
370
|
+
"settings.models.add": "+ Add Model",
|
|
371
|
+
"settings.models.loading": "Loading models…",
|
|
372
|
+
"settings.models.error": "Failed to load: {{msg}}",
|
|
373
|
+
"settings.models.empty": "No models configured. Click \"+ Add Model\" to add one.",
|
|
374
|
+
"settings.models.badge.default": "Default",
|
|
375
|
+
"settings.models.badge.lite": "Lite",
|
|
376
|
+
"settings.models.field.quicksetup": "Quick Setup",
|
|
377
|
+
"settings.models.field.model": "Model",
|
|
378
|
+
"settings.models.field.baseurl": "Base URL",
|
|
379
|
+
"settings.models.field.apikey": "API Key",
|
|
380
|
+
"settings.models.field.getApiKey": "How to get →",
|
|
381
|
+
"settings.models.field.docsGuide.question": "New to AI keys?",
|
|
382
|
+
"settings.models.field.docsGuide.cta": "See the guide →",
|
|
383
|
+
"settings.models.placeholder.provider": "— Choose provider —",
|
|
384
|
+
"settings.models.placeholder.model": "e.g. claude-sonnet-4-5",
|
|
385
|
+
"settings.models.placeholder.baseurl": "https://api.anthropic.com",
|
|
386
|
+
"settings.models.placeholder.apikey": "sk-…",
|
|
387
|
+
"settings.models.custom": "Custom",
|
|
388
|
+
"settings.models.baseurl.noVariants": "No preset endpoints available",
|
|
389
|
+
"settings.models.baseurl.variant.mainland_cn": "Mainland China",
|
|
390
|
+
"settings.models.baseurl.variant.international": "International",
|
|
391
|
+
"settings.models.baseurl.variant.mainland_cn_payg": "Mainland · Pay-as-you-go",
|
|
392
|
+
"settings.models.baseurl.variant.mainland_cn_coding": "Mainland · Coding Plan",
|
|
393
|
+
"settings.models.baseurl.variant.international_payg": "International · Pay-as-you-go",
|
|
394
|
+
"settings.models.baseurl.variant.international_coding": "International · Coding Plan",
|
|
395
|
+
"settings.models.btn.save": "Save",
|
|
396
|
+
"settings.models.btn.saving": "Saving…",
|
|
397
|
+
"settings.models.btn.saved": "Saved ✓",
|
|
398
|
+
"settings.models.btn.testing": "Testing…",
|
|
399
|
+
"settings.models.btn.set_default": "Set as Default",
|
|
400
|
+
"settings.models.btn.setDefault": "Set as Default",
|
|
401
|
+
"settings.models.btn.setting": "Setting…",
|
|
402
|
+
"settings.models.btn.done": "Done ✓",
|
|
403
|
+
"settings.models.test.ok": "✓ Connected",
|
|
404
|
+
"settings.models.test.fail": "✗ Test fail: {{msg}}",
|
|
405
|
+
"settings.models.badge.model": "Model {{n}}",
|
|
406
|
+
"settings.models.connected": "Connected",
|
|
407
|
+
"settings.models.testFail": "Test fail",
|
|
408
|
+
"settings.models.failed": "Failed",
|
|
409
|
+
"settings.models.saveFailed": "Save failed",
|
|
410
|
+
"settings.models.setDefaultFailed": "Failed to set default model",
|
|
411
|
+
"settings.models.errorPrefix": "Error: ",
|
|
412
|
+
"settings.models.confirmRemove": "Remove model \"{{model}}\"?",
|
|
413
|
+
"settings.personalize.title": "Personalize",
|
|
414
|
+
"settings.personalize.desc": "Re-run the onboarding to update your assistant's personality and user profile (SOUL.md & USER.md).",
|
|
415
|
+
"settings.personalize.btn": "✨ Re-run Onboard",
|
|
416
|
+
"settings.personalize.btn.starting": "Starting…",
|
|
417
|
+
"settings.personalize.btn.rerun": "✨ Re-run Onboard",
|
|
418
|
+
"settings.browser.title": "Browser",
|
|
419
|
+
"settings.browser.desc": "Connect your browser to enable browser automation.",
|
|
420
|
+
"settings.browser.configured": "✅ Browser connected",
|
|
421
|
+
"settings.browser.disabled": "⏸ Browser disabled",
|
|
422
|
+
"settings.browser.btn": "🌐 Configure Browser",
|
|
423
|
+
"settings.browser.btn.reconfigure": "🌐 Reconfigure Browser",
|
|
424
|
+
"settings.browser.btn.starting": "Starting…",
|
|
425
|
+
|
|
426
|
+
"settings.lang.title": "Language",
|
|
427
|
+
"settings.lang.en": "English",
|
|
428
|
+
"settings.lang.zh": "中文",
|
|
429
|
+
|
|
430
|
+
"settings.fontSize.title": "Font Size",
|
|
431
|
+
"settings.fontSize.small": "Small",
|
|
432
|
+
"settings.fontSize.medium": "Medium",
|
|
433
|
+
"settings.fontSize.large": "Large",
|
|
434
|
+
|
|
435
|
+
"settings.currency.title": "Currency",
|
|
436
|
+
"settings.currency.usd": "$ USD",
|
|
437
|
+
"settings.currency.cny": "¥ CNY",
|
|
438
|
+
|
|
439
|
+
// ── Onboard ──
|
|
440
|
+
"onboard.title": "Welcome to {{brand}}",
|
|
441
|
+
"onboard.subtitle": "Let's get you set up in a minute.",
|
|
442
|
+
"onboard.lang.prompt": "Choose your language",
|
|
443
|
+
"onboard.key.title": "Connect your AI model",
|
|
444
|
+
"onboard.key.provider": "Provider",
|
|
445
|
+
"onboard.key.provider.placeholder": "— Choose provider —",
|
|
446
|
+
"onboard.key.model": "Model",
|
|
447
|
+
"onboard.key.baseurl": "Base URL",
|
|
448
|
+
"onboard.key.apikey": "API Key",
|
|
449
|
+
"onboard.key.getApiKey": "How to get →",
|
|
450
|
+
"onboard.key.docsGuide.question": "New to AI keys?",
|
|
451
|
+
"onboard.key.docsGuide.cta": "See the guide →",
|
|
452
|
+
"onboard.key.btn.test": "Test & Continue →",
|
|
453
|
+
"onboard.key.btn.back": "← Back",
|
|
454
|
+
"onboard.provider.custom": "Custom",
|
|
455
|
+
"provider.recommended": "Recommended",
|
|
456
|
+
"onboard.key.testing": "Testing…",
|
|
457
|
+
"onboard.key.saving": "Saving…",
|
|
458
|
+
"onboard.soul.title": "Personalize your assistant",
|
|
459
|
+
"onboard.soul.desc": "Takes about 30 seconds. You'll be asked two quick questions via interactive cards.",
|
|
460
|
+
"onboard.soul.btn.start": "Let's go →",
|
|
461
|
+
"onboard.soul.btn.skip": "Skip for now",
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
// ── Session info bar / Model switcher benchmark ──
|
|
467
|
+
"sib.bench.btn": "Benchmark",
|
|
468
|
+
"sib.bench.tooltip": "Test response latency for every configured model",
|
|
469
|
+
"sib.bench.running": "Testing…",
|
|
470
|
+
"sib.bench.done": "done in {{t}}s",
|
|
471
|
+
"sib.bench.failed": "failed: {{msg}}",
|
|
472
|
+
"sib.bench.latencyTooltip": "TTFT {{ttft}} · tested {{time}}",
|
|
473
|
+
|
|
474
|
+
"onboard.welcome": "Welcome to {{name}}",
|
|
475
|
+
},
|
|
476
|
+
|
|
477
|
+
zh: {
|
|
478
|
+
// ── Sidebar ──
|
|
479
|
+
"sidebar.chat": "会话",
|
|
480
|
+
"sidebar.config": "配置",
|
|
481
|
+
"sidebar.tasks": "任务管理",
|
|
482
|
+
"sidebar.skills": "技能管理",
|
|
483
|
+
"sidebar.channels": "频道管理",
|
|
484
|
+
"sidebar.trash": "文件召回",
|
|
485
|
+
"sidebar.profile": "助理记忆",
|
|
486
|
+
"sidebar.memories": "记忆",
|
|
487
|
+
"sidebar.dataSection": "我的数据",
|
|
488
|
+
"sidebar.settings": "设置",
|
|
489
|
+
|
|
490
|
+
// ── Welcome screen ──
|
|
491
|
+
"welcome.title": "欢迎使用 {{brand}}",
|
|
492
|
+
"welcome.body": "新建会话,或从左侧选择一个已有会话。",
|
|
493
|
+
"welcome.btn": "新建会话",
|
|
494
|
+
|
|
495
|
+
// ── Chat panel ──
|
|
496
|
+
"chat.status.idle": "空闲",
|
|
497
|
+
"chat.status.running": "运行中",
|
|
498
|
+
"chat.status.error": "出错",
|
|
499
|
+
// ── Background tasks (fire-and-forget) ──
|
|
500
|
+
"bgtasks.badge": "🔄 {{n}} 个后台任务",
|
|
501
|
+
"bgtasks.tooltip": "悬浮查看详情 · 点击展开",
|
|
502
|
+
"bgtasks.notice": "后台任务 {{status}}:",
|
|
503
|
+
// ── Inbox queue hint (above the input bar) ──
|
|
504
|
+
"inbox.queue.one": "1 条消息排队中 — agent 处理完手头的事会马上看。",
|
|
505
|
+
"inbox.queue.many": "{{n}} 条消息排队中 — agent 处理完手头的事会马上看。",
|
|
506
|
+
"chat.input.placeholder": "输入消息…(Enter 发送,Shift+Enter 换行)",
|
|
507
|
+
"chat.input.placeholderRunning": "AI 正在工作,你仍然可以随时补充新信息给它...",
|
|
508
|
+
"chat.input.placeholderMobile": "输入消息…",
|
|
509
|
+
"chat.input.placeholderRunningMobile": "可输入补充消息…",
|
|
510
|
+
"chat.btn.send": "发送",
|
|
511
|
+
"chat.thinking": "思考中…",
|
|
512
|
+
"chat.retrying": "正在重试",
|
|
513
|
+
"chat.history_load_failed": "历史记录加载失败",
|
|
514
|
+
"chat.history_start": "没有更多历史了",
|
|
515
|
+
"chat.image_expired": "已过期",
|
|
516
|
+
"chat.done": "完成 — {{n}} 步",
|
|
517
|
+
"chat.done.duration": " · {{duration}}s",
|
|
518
|
+
"chat.done.cache": "缓存命中 {{rate}}% ({{hits}}/{{total}}) · 复用 {{tokens}} tokens",
|
|
519
|
+
"chat.interrupted": "已中断。",
|
|
520
|
+
"chat.feedback_hint": "或在下方输入框自由作答 ↓",
|
|
521
|
+
"chat.newMessageHint": "有新消息 ↓",
|
|
522
|
+
"chat.retry": "重试",
|
|
523
|
+
"chat.copy": "复制",
|
|
524
|
+
"chat.copied": "已复制",
|
|
525
|
+
"chat.empty.title": "开始新会话",
|
|
526
|
+
"chat.empty.subtitle": "直接提问,或用一个 Skill 启动。",
|
|
527
|
+
"chat.empty.tip1": "输入 / 浏览 Skill",
|
|
528
|
+
"chat.empty.tip2": "可粘贴或拖入图片、PDF、文档",
|
|
529
|
+
"chat.empty.tip3": "Shift+Enter 换行",
|
|
530
|
+
"chat.empty.tip4": "每个会话上下文独立,但长期记忆全局共享",
|
|
531
|
+
|
|
532
|
+
// ── Session list ──
|
|
533
|
+
"sessions.empty": "暂无会话",
|
|
534
|
+
"sessions.confirmDelete": "删除会话 {{name}}?此操作不可撤销。",
|
|
535
|
+
"sessions.meta": "{{tasks}} 个任务",
|
|
536
|
+
"sessions.metaTasks": "{{n}} 个任务",
|
|
537
|
+
"sessions.deleteTitle": "删除会话",
|
|
538
|
+
"sessions.createError": "错误:",
|
|
539
|
+
"sessions.dirNotEmpty": "该目录已存在且不为空,请换一个目录名。",
|
|
540
|
+
"sessions.export.tooltip": "下载会话文件(session.json + 归档片段 + 当天日志),用于调试",
|
|
541
|
+
"sessions.export.failed": "下载会话文件失败",
|
|
542
|
+
"sessions.actions.tooltip": "点击查看会话操作",
|
|
543
|
+
"sessions.actions.download": "下载会话文件",
|
|
544
|
+
"sessions.actions.downloadHint": "用于调试",
|
|
545
|
+
"sib.dir.tooltip": "点击切换工作目录",
|
|
546
|
+
"sib.dir.changePrompt": "切换工作目录:",
|
|
547
|
+
"sib.model.tooltip": "点击切换模型",
|
|
548
|
+
"sib.signal.tooltip": "最近一次 LLM 响应延迟",
|
|
549
|
+
"sib.reasoning.tooltip": "点击调整思考等级",
|
|
550
|
+
"sib.reasoning.label": "思考",
|
|
551
|
+
"sib.reasoning.heading": "思考等级",
|
|
552
|
+
"sib.reasoning.hint": "等级越高,思考越深,响应越慢。",
|
|
553
|
+
"sib.reasoning.off": "默认",
|
|
554
|
+
"sib.reasoning.low": "低",
|
|
555
|
+
"sib.reasoning.medium": "中",
|
|
556
|
+
"sib.reasoning.high": "高",
|
|
557
|
+
"sessions.thinking": "思考中…",
|
|
558
|
+
"sessions.default_name": "会话 {{n}}",
|
|
559
|
+
"sessions.cronGroup": "定时任务",
|
|
560
|
+
"sessions.cronGroupMeta": "{{n}} 个会话",
|
|
561
|
+
"sessions.cronLoading": "正在加载定时任务...",
|
|
562
|
+
"sessions.badge.cron": "定时",
|
|
563
|
+
"sessions.badge.channel": "频道",
|
|
564
|
+
"sessions.badge.coding": "Coding",
|
|
565
|
+
"sessions.badge.setup": "配置",
|
|
566
|
+
"sessions.newSession": "+ 新会话",
|
|
567
|
+
"sessions.newSessionAdvanced": "更多选项",
|
|
568
|
+
"sessions.loadMore": "加载更多会话",
|
|
569
|
+
"sessions.actions.pin": "置顶",
|
|
570
|
+
"sessions.actions.unpin": "取消置顶",
|
|
571
|
+
"sessions.actions.rename": "重命名",
|
|
572
|
+
"sessions.actions.delete": "删除",
|
|
573
|
+
"sessions.loadingMore": "加载中…",
|
|
574
|
+
"sessions.search.placeholder": "搜索会话…",
|
|
575
|
+
"sessions.search.typeAll": "全部类型",
|
|
576
|
+
"sessions.search.typeManual": "默认",
|
|
577
|
+
"sessions.search.typeCron": "定时",
|
|
578
|
+
"sessions.search.typeChannel": "频道",
|
|
579
|
+
"sessions.search.typeCoding": "Coding",
|
|
580
|
+
"sessions.search.typeSetup": "配置",
|
|
581
|
+
"sessions.search.datePlaceholder": "日期",
|
|
582
|
+
"modal.yes": "确定",
|
|
583
|
+
"modal.no": "取消",
|
|
584
|
+
"modal.ok": "确定",
|
|
585
|
+
"modal.cancel": "取消",
|
|
586
|
+
|
|
587
|
+
// ── Auth ──
|
|
588
|
+
"auth.accessKeyRequired": "请输入访问密钥:",
|
|
589
|
+
"auth.rateLimited": "尝试次数过多,请 {{seconds}} 秒后再试。",
|
|
590
|
+
|
|
591
|
+
// ── New Session Modal ──
|
|
592
|
+
"sessions.modal.title": "创建新会话",
|
|
593
|
+
"sessions.modal.agent": "助手类型",
|
|
594
|
+
"sessions.modal.agent.general": "通用",
|
|
595
|
+
"sessions.modal.agent.coding": "编程",
|
|
596
|
+
"sessions.modal.name": "会话名称",
|
|
597
|
+
"sessions.modal.name.placeholder": "留空自动生成",
|
|
598
|
+
"sessions.modal.model": "模型",
|
|
599
|
+
"sessions.modal.directory": "工作目录",
|
|
600
|
+
"sessions.modal.directory.placeholder": "~/octo_workspace",
|
|
601
|
+
"sessions.modal.initProject": "初始化全栈项目 (/new)",
|
|
602
|
+
"sessions.modal.create": "创建会话",
|
|
603
|
+
|
|
604
|
+
// ── Offline banner ──
|
|
605
|
+
"offline.banner": "服务已断开,正在重连…",
|
|
606
|
+
"chat.disconnected.hint": "服务已断开,请等待重连后再发送。",
|
|
607
|
+
|
|
608
|
+
// ── Version / Upgrade ──
|
|
609
|
+
"upgrade.desc": "有新版本可用,将在后台安装,升级期间可继续使用。",
|
|
610
|
+
"upgrade.btn.upgrade": "立即升级",
|
|
611
|
+
"upgrade.btn.cancel": "取消",
|
|
612
|
+
"upgrade.btn.restart": "↻ 立即重启",
|
|
613
|
+
"upgrade.installing": "安装中…",
|
|
614
|
+
"upgrade.done": "升级完成!",
|
|
615
|
+
"upgrade.failed": "升级失败,请重试或手动执行:gem update octo",
|
|
616
|
+
"upgrade.reconnecting": "服务重启中…",
|
|
617
|
+
"upgrade.restart.success": "✓ 重启成功!",
|
|
618
|
+
"upgrade.restart.timeout.title": "热重启未完成",
|
|
619
|
+
"upgrade.restart.timeout.desc": "服务在 30 秒内未恢复。请通过以下任一方式重启:",
|
|
620
|
+
"upgrade.restart.timeout.tray": "在系统托盘菜单中选择「退出」,然后重新打开应用。",
|
|
621
|
+
"upgrade.restart.timeout.cli": "如果是终端启动,请执行命令: {{cmd}}",
|
|
622
|
+
"upgrade.restart.timeout.retry": "重试",
|
|
623
|
+
"upgrade.tooltip.upgrading": "升级中,点击查看进度",
|
|
624
|
+
"upgrade.tooltip.new": "v{{latest}} 可用,点击升级",
|
|
625
|
+
"upgrade.tooltip.ok": "v{{current}}(已是最新)",
|
|
626
|
+
"upgrade.tooltip.needs_restart": "升级完成,点击重启",
|
|
627
|
+
"upgrade.tooltip.done": "重启成功",
|
|
628
|
+
|
|
629
|
+
// ── Tasks panel ──
|
|
630
|
+
"tasks.title": "定时任务",
|
|
631
|
+
"tasks.subtitle": "管理和调度助手的自动化任务",
|
|
632
|
+
"tasks.btn.create": "创建任务",
|
|
633
|
+
"tasks.btn.createTask": "创建任务",
|
|
634
|
+
"tasks.empty": "(空)",
|
|
635
|
+
"tasks.noScheduled": "暂无定时任务。",
|
|
636
|
+
"tasks.noTasks": "无任务",
|
|
637
|
+
"tasks.count": "{{n}} 个任务",
|
|
638
|
+
"tasks.manual": "手动",
|
|
639
|
+
"tasks.col.name": "名称",
|
|
640
|
+
"tasks.col.schedule": "计划",
|
|
641
|
+
"tasks.col.task": "任务内容",
|
|
642
|
+
"tasks.btn.run": "立即运行",
|
|
643
|
+
"tasks.btn.edit": "编辑",
|
|
644
|
+
"tasks.btn.pause": "暂停",
|
|
645
|
+
"tasks.btn.resume": "启用",
|
|
646
|
+
"tasks.paused": "已暂停",
|
|
647
|
+
"tasks.toggleError": "更新任务失败。",
|
|
648
|
+
"tasks.runError": "错误:",
|
|
649
|
+
"tasks.sessionError": "创建会话失败:",
|
|
650
|
+
"tasks.confirmDelete": "删除任务「{{name}}」?",
|
|
651
|
+
"tasks.deleteError": "删除任务失败。",
|
|
652
|
+
"tasks.label.active": "任务",
|
|
653
|
+
"tasks.label.none": "无任务",
|
|
654
|
+
|
|
655
|
+
// ── Skills panel ──
|
|
656
|
+
"skills.title": "技能",
|
|
657
|
+
"skills.subtitle": "为助手添加自定义能力",
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
|
|
666
|
+
|
|
667
|
+
// ── Creator trash ──
|
|
668
|
+
"trash.title": "文件召回",
|
|
669
|
+
"trash.subtitle": "AI 代理在各个项目里丢进回收站的文件。可以把它们召回到原位置,或彻底清理不再需要的。",
|
|
670
|
+
"trash.refresh": "刷新",
|
|
671
|
+
"trash.emptyOld": "清理 >7 天",
|
|
672
|
+
"trash.emptyOrphans":"清理孤儿",
|
|
673
|
+
"trash.emptyAll": "全部清空",
|
|
674
|
+
"trash.empty": "回收站空空如也。",
|
|
675
|
+
"trash.loading": "加载回收站…",
|
|
676
|
+
"trash.summary": "共 {{count}} 个文件,{{size}}",
|
|
677
|
+
"trash.summaryOrphans": "其中 {{count}} 条孤儿",
|
|
678
|
+
"trash.orphan": "孤儿",
|
|
679
|
+
"trash.orphanHint": "原项目目录已不存在(通常来自测试临时目录)。可以安全地永久删除。",
|
|
680
|
+
"trash.noOrphans": "未检测到孤儿条目。",
|
|
681
|
+
"trash.project": "项目",
|
|
682
|
+
"trash.deletedAt": "删除于",
|
|
683
|
+
"trash.restore": "恢复",
|
|
684
|
+
"trash.delete": "删除",
|
|
685
|
+
"trash.restoreOk": "已恢复:{{path}}",
|
|
686
|
+
"trash.restoreFail": "恢复失败:{{msg}}",
|
|
687
|
+
"trash.confirmDeleteOne": "永久删除 \"{{name}}\"?\n此操作不可撤销。",
|
|
688
|
+
"trash.confirmEmptyOld": "永久删除所有超过 7 天的回收站文件?\n此操作不可撤销。",
|
|
689
|
+
"trash.confirmEmptyAll": "永久删除所有项目的全部回收站文件?\n此操作不可撤销。",
|
|
690
|
+
"trash.confirmEmptyOrphans": "永久删除 {{count}} 条原项目已消失的孤儿条目?\n此操作不可撤销。",
|
|
691
|
+
"trash.emptied": "已永久删除 {{count}} 个文件,释放 {{size}}。",
|
|
692
|
+
"trash.orphansCleaned": "已清理 {{count}} 条孤儿,释放 {{size}}。(失败 {{failed}})",
|
|
693
|
+
"trash.nothingOld": "没有超过 7 天的文件。",
|
|
694
|
+
|
|
695
|
+
// ── Profile (助理记忆 — USER.md / SOUL.md / 记忆 统一只读视图) ──
|
|
696
|
+
"profile.title": "助理记忆",
|
|
697
|
+
"profile.subtitle": "这是一扇通往 AI 内心的窗口:它是谁、你是谁、以及它在和你共事中记住了什么。",
|
|
698
|
+
"profile.whoIAm": "我是谁",
|
|
699
|
+
"profile.whoYouAre": "你是谁",
|
|
700
|
+
"profile.statusDefault": "当前使用内置默认",
|
|
701
|
+
"profile.statusCustom": "已启用自定义",
|
|
702
|
+
"profile.loadFail": "加载失败",
|
|
703
|
+
"profile.emptyContent": "(无内容)",
|
|
704
|
+
|
|
705
|
+
// Profile tabs
|
|
706
|
+
"profile.tab.soul": "助理性格",
|
|
707
|
+
"profile.tab.user": "主人设定",
|
|
708
|
+
"profile.tab.memories": "记忆管理",
|
|
709
|
+
|
|
710
|
+
// Per-tab curate actions
|
|
711
|
+
"profile.soul.curateHint": "感觉不太对?让助理通过一段简短对话帮你调整。",
|
|
712
|
+
"profile.soul.curateBtn": "让助理整理性格",
|
|
713
|
+
"profile.user.curateHint": "换工作了?有新兴趣了?让助理帮你更新主人档案。",
|
|
714
|
+
"profile.user.curateBtn": "让助理更新档案",
|
|
715
|
+
"profile.curateFail": "无法启动整理会话",
|
|
716
|
+
"profile.curateName.soul": "整理性格",
|
|
717
|
+
"profile.curateName.user": "整理主人档案",
|
|
718
|
+
|
|
719
|
+
// 旧 keys(兼容保留)
|
|
720
|
+
"profile.update": "更新资料",
|
|
721
|
+
"profile.updateFail": "无法启动更新会话",
|
|
722
|
+
"profile.user.placeholder": "告诉助手你的信息 —— 姓名、角色、偏好、工作风格……",
|
|
723
|
+
"profile.soul.placeholder": "描述助手的性格 —— 语气、价值观、沟通风格……",
|
|
724
|
+
"profile.save": "保存",
|
|
725
|
+
"profile.reset": "恢复默认",
|
|
726
|
+
"profile.savedOk": "已保存 ✓",
|
|
727
|
+
"profile.resetOk": "已恢复默认 ✓",
|
|
728
|
+
"profile.saveFail": "保存失败",
|
|
729
|
+
"profile.confirmReset": "确认清空自定义内容,恢复为内置默认吗?",
|
|
730
|
+
|
|
731
|
+
// ── Memories(嵌在助理记忆页) ──
|
|
732
|
+
"memories.title": "记忆",
|
|
733
|
+
"memories.subtitle": "保存在 ~/.octo/memories/ 的长期记忆,按最近更新倒序。点击「整理」让助理帮你打理这条记忆,或点击「删除」丢弃。",
|
|
734
|
+
"memories.curate": "整理",
|
|
735
|
+
"memories.curateTitle": "开启一个会话,让助理和你一起整理这条记忆",
|
|
736
|
+
"memories.curateFail": "无法启动记忆会话",
|
|
737
|
+
"memories.curateName": "整理记忆",
|
|
738
|
+
"memories.delete": "删除",
|
|
739
|
+
"memories.deleteTitle": "删除这条记忆",
|
|
740
|
+
"memories.deleteFail": "删除失败",
|
|
741
|
+
"memories.confirmDelete": "删除记忆 \"{{name}}\" 吗?\n会先放入「文件召回」,仍可从那里找回。",
|
|
742
|
+
"memories.expandTitle": "展开完整内容",
|
|
743
|
+
"memories.reloadList": "↻ 刷新列表",
|
|
744
|
+
"memories.loading": "加载中…",
|
|
745
|
+
"memories.empty": "还没有记忆。助手会在后续工作中自动创建。",
|
|
746
|
+
"memories.emptyHint": "",
|
|
747
|
+
"memories.summary": "共 {{count}} 条记忆",
|
|
748
|
+
// 旧 keys(兼容保留)
|
|
749
|
+
"memories.refresh": "整理",
|
|
750
|
+
"memories.refreshTitle": "开启一个会话,让助理和你一起整理这条记忆",
|
|
751
|
+
"memories.refreshFail": "无法启动记忆会话",
|
|
752
|
+
"memories.new": "+ 新建记忆",
|
|
753
|
+
"memories.edit": "编辑",
|
|
754
|
+
"memories.save": "保存",
|
|
755
|
+
"memories.cancel": "取消",
|
|
756
|
+
"memories.filenamePh": "topic-name.md",
|
|
757
|
+
"memories.contentPh": "Markdown 内容,可带 YAML frontmatter…",
|
|
758
|
+
"memories.filenameRequired": "请填写文件名(如 topic-name.md)。",
|
|
759
|
+
|
|
760
|
+
"skills.btn.new": "新建技能",
|
|
761
|
+
"skills.btn.create": "创建",
|
|
762
|
+
"skills.btn.import": "导入",
|
|
763
|
+
"skills.import.placeholder": "粘贴 ZIP 或 GitHub 链接…",
|
|
764
|
+
"skills.import.install": "安装",
|
|
765
|
+
"skills.tab.my": "我的技能",
|
|
766
|
+
"skills.empty": "暂无技能。",
|
|
767
|
+
"skills.empty.createBtn": "用 /skill-creator 创建新技能",
|
|
768
|
+
"skills.noSkills": "无技能",
|
|
769
|
+
"skills.count": "{{n}} 个技能",
|
|
770
|
+
"skills.loading": "加载中…",
|
|
771
|
+
"skills.badge.system": "系统",
|
|
772
|
+
"skills.badge.custom": "自定义",
|
|
773
|
+
"skills.badge.invalid": "无效",
|
|
774
|
+
"skills.btn.use": "使用",
|
|
775
|
+
"skills.filter.showSystem": "显示系统技能",
|
|
776
|
+
"skills.filter.showSystemShort": "显示系统",
|
|
777
|
+
"skills.systemDisabledTip": "系统技能不可禁用",
|
|
778
|
+
"skills.invalid.reason": "该技能配置有误,无法使用。",
|
|
779
|
+
"skills.invalid.toggleTip": "无效技能无法启用",
|
|
780
|
+
"skills.warning.tooltip": "该技能配置有小问题,但仍然可以正常使用。\n原因:{{reason}}",
|
|
781
|
+
"skills.toggle.disable": "禁用技能",
|
|
782
|
+
"skills.toggle.enable": "启用技能",
|
|
783
|
+
"skills.toggle.disableDesc": "AI 可自动调用。关闭后 AI 不会主动触发(手动使用仍可用)",
|
|
784
|
+
"skills.toggle.enableDesc": "AI 不会自动调用。开启后允许 AI 主动触发",
|
|
785
|
+
"skills.toggleError": "错误:",
|
|
786
|
+
"skills.ac.empty": "暂无可用技能",
|
|
787
|
+
"skills.upload.uploading": "上传中…",
|
|
788
|
+
"skills.upload.uploaded": "已上传",
|
|
789
|
+
"skills.upload.upload": "上传",
|
|
790
|
+
"skills.upload.failed": "失败",
|
|
791
|
+
"skills.upload.publishTip": "发布到云端",
|
|
792
|
+
"skills.btn.refresh": "刷新",
|
|
793
|
+
|
|
794
|
+
// ── Channels panel ──
|
|
795
|
+
"channels.title": "频道",
|
|
796
|
+
"channels.subtitle": "连接即时通讯平台,让用户通过飞书、企业微信、微信、Discord、Telegram 或钉钉与助手对话",
|
|
797
|
+
"channels.loading": "加载中…",
|
|
798
|
+
"channels.loadError": "加载频道失败:{{msg}}",
|
|
799
|
+
"channels.badge.running": "运行中",
|
|
800
|
+
"channels.badge.enabled": "已启用",
|
|
801
|
+
"channels.badge.disabled": "已关闭",
|
|
802
|
+
"channels.badge.notConfigured": "未配置",
|
|
803
|
+
"channels.hint.running": "适配器运行中,正在接受用户消息",
|
|
804
|
+
"channels.hint.enabled": "⚠ 已启用但未运行 — 适配器可能连接失败,请点击「诊断问题」排查。",
|
|
805
|
+
"channels.hint.enabledNotRunning":"已启用但未运行 — 适配器可能连接失败,请点击「诊断问题」排查。",
|
|
806
|
+
"channels.hint.idle": "尚未配置。点击「用 Agent 配置」开始。",
|
|
807
|
+
"channels.hint.notConfigured": "尚未配置。点击「用 Agent 配置」开始。",
|
|
808
|
+
"channels.hint.disabled": "已配置但已关闭,使用开关重新启用。",
|
|
809
|
+
"channels.toggle.on": "已启用 — 点击关闭",
|
|
810
|
+
"channels.toggle.off": "已关闭 — 点击启用",
|
|
811
|
+
"channels.btn.test": "诊断问题",
|
|
812
|
+
"channels.btn.setup": "用 Agent 配置",
|
|
813
|
+
"channels.btn.reconfig": "重新配置",
|
|
814
|
+
"channels.btn.reconfigure": "重新配置",
|
|
815
|
+
"channels.sessionError": "未知",
|
|
816
|
+
"channels.noSession": "未返回会话",
|
|
817
|
+
"channels.feishu.desc": "通过飞书开放平台 WebSocket 长连接接入",
|
|
818
|
+
"channels.wecom.desc": "通过企业微信智能机器人 WebSocket 接入",
|
|
819
|
+
"channels.weixin.desc": "通过微信 iLink 机器人接入(扫码登录,HTTP 长轮询)",
|
|
820
|
+
"channels.discord.desc": "通过 Discord 机器人接入,授权链接邀请 Bot 加入服务器",
|
|
821
|
+
"channels.telegram.desc": "通过 Telegram Bot API 接入(HTTPS 长轮询,token 来自 @BotFather)",
|
|
822
|
+
"channels.dingtalk.desc": "通过钉钉 Stream 模式 WebSocket 接入",
|
|
823
|
+
|
|
824
|
+
// ── Settings panel ──
|
|
825
|
+
"settings.title": "设置",
|
|
826
|
+
"settings.models.title": "AI 模型",
|
|
827
|
+
"settings.models.add": "+ 添加模型",
|
|
828
|
+
"settings.models.loading": "加载模型中…",
|
|
829
|
+
"settings.models.error": "加载失败:{{msg}}",
|
|
830
|
+
"settings.models.empty": "暂未配置模型,点击「+ 添加模型」添加。",
|
|
831
|
+
"settings.models.badge.default": "默认",
|
|
832
|
+
"settings.models.badge.lite": "轻量",
|
|
833
|
+
"settings.models.field.quicksetup": "快速配置",
|
|
834
|
+
"settings.models.field.model": "Model",
|
|
835
|
+
"settings.models.field.baseurl": "Base URL",
|
|
836
|
+
"settings.models.field.apikey": "API Key",
|
|
837
|
+
"settings.models.field.getApiKey": "如何获取 →",
|
|
838
|
+
"settings.models.field.docsGuide.question": "不会配置 AI 模型?",
|
|
839
|
+
"settings.models.field.docsGuide.cta": "查看指南 →",
|
|
840
|
+
"settings.models.placeholder.provider": "— 选择服务商 —",
|
|
841
|
+
"settings.models.placeholder.model": "如 claude-sonnet-4-5",
|
|
842
|
+
"settings.models.placeholder.baseurl": "https://api.anthropic.com",
|
|
843
|
+
"settings.models.placeholder.apikey": "sk-…",
|
|
844
|
+
"settings.models.custom": "自定义",
|
|
845
|
+
"settings.models.baseurl.noVariants": "暂无预设端点",
|
|
846
|
+
"settings.models.baseurl.variant.mainland_cn": "中国大陆",
|
|
847
|
+
"settings.models.baseurl.variant.international": "海外",
|
|
848
|
+
"settings.models.baseurl.variant.mainland_cn_payg": "大陆 · 按量付费",
|
|
849
|
+
"settings.models.baseurl.variant.mainland_cn_coding": "大陆 · Coding Plan",
|
|
850
|
+
"settings.models.baseurl.variant.international_payg": "海外 · 按量付费",
|
|
851
|
+
"settings.models.baseurl.variant.international_coding": "海外 · Coding Plan",
|
|
852
|
+
"settings.models.btn.save": "保存",
|
|
853
|
+
"settings.models.btn.saving": "保存中…",
|
|
854
|
+
"settings.models.btn.saved": "已保存 ✓",
|
|
855
|
+
"settings.models.btn.testing": "测试中…",
|
|
856
|
+
"settings.models.btn.set_default": "设为默认",
|
|
857
|
+
"settings.models.btn.setDefault": "设为默认",
|
|
858
|
+
"settings.models.btn.setting": "设置中…",
|
|
859
|
+
"settings.models.btn.done": "完成 ✓",
|
|
860
|
+
"settings.models.test.ok": "✓ 连接成功",
|
|
861
|
+
"settings.models.test.fail": "✗ 测试失败:{{msg}}",
|
|
862
|
+
"settings.models.badge.model": "模型 {{n}}",
|
|
863
|
+
"settings.models.connected": "已连接",
|
|
864
|
+
"settings.models.testFail": "测试失败",
|
|
865
|
+
"settings.models.failed": "失败",
|
|
866
|
+
"settings.models.saveFailed": "保存失败",
|
|
867
|
+
"settings.models.setDefaultFailed": "设置默认模型失败",
|
|
868
|
+
"settings.models.errorPrefix": "错误:",
|
|
869
|
+
"settings.models.confirmRemove": "删除模型「{{model}}」?",
|
|
870
|
+
"settings.personalize.title": "个性化",
|
|
871
|
+
"settings.personalize.desc": "重新运行引导流程,更新助手的个性和用户档案(SOUL.md & USER.md)。",
|
|
872
|
+
"settings.personalize.btn": "✨ 重新引导",
|
|
873
|
+
"settings.personalize.btn.starting": "启动中…",
|
|
874
|
+
"settings.personalize.btn.rerun": "✨ 重新引导",
|
|
875
|
+
"settings.browser.title": "浏览器",
|
|
876
|
+
"settings.browser.desc": "连接浏览器以启用浏览器自动化功能。",
|
|
877
|
+
"settings.browser.configured": "✅ 浏览器已连接",
|
|
878
|
+
"settings.browser.disabled": "⏸ 浏览器已禁用",
|
|
879
|
+
"settings.browser.btn": "🌐 配置浏览器",
|
|
880
|
+
"settings.browser.btn.reconfigure": "🌐 重新配置浏览器",
|
|
881
|
+
"settings.browser.btn.starting": "启动中…",
|
|
882
|
+
|
|
883
|
+
"settings.lang.title": "语言",
|
|
884
|
+
"settings.lang.en": "English",
|
|
885
|
+
"settings.lang.zh": "中文",
|
|
886
|
+
|
|
887
|
+
"settings.fontSize.title": "字体大小",
|
|
888
|
+
"settings.fontSize.small": "小",
|
|
889
|
+
"settings.fontSize.medium": "中",
|
|
890
|
+
"settings.fontSize.large": "大",
|
|
891
|
+
|
|
892
|
+
"settings.currency.title": "货币",
|
|
893
|
+
"settings.currency.usd": "$ 美元",
|
|
894
|
+
"settings.currency.cny": "¥ 人民币",
|
|
895
|
+
|
|
896
|
+
// ── Onboard ──
|
|
897
|
+
"onboard.title": "欢迎使用 {{brand}}",
|
|
898
|
+
"onboard.subtitle": "一分钟完成配置,马上开始。",
|
|
899
|
+
"onboard.lang.prompt": "选择您的语言",
|
|
900
|
+
"onboard.key.title": "连接 AI 模型",
|
|
901
|
+
"onboard.key.provider": "服务商",
|
|
902
|
+
"onboard.key.provider.placeholder": "— 选择服务商 —",
|
|
903
|
+
"onboard.key.model": "模型",
|
|
904
|
+
"onboard.key.baseurl": "Base URL",
|
|
905
|
+
"onboard.key.apikey": "API Key",
|
|
906
|
+
"onboard.key.getApiKey": "如何获取 →",
|
|
907
|
+
"onboard.key.docsGuide.question": "不会配置 AI 模型?",
|
|
908
|
+
"onboard.key.docsGuide.cta": "查看指南 →",
|
|
909
|
+
"onboard.key.btn.test": "测试并继续 →",
|
|
910
|
+
"onboard.key.btn.back": "← 返回",
|
|
911
|
+
"onboard.provider.custom": "自定义",
|
|
912
|
+
"provider.recommended": "推荐",
|
|
913
|
+
"onboard.key.testing": "测试中…",
|
|
914
|
+
"onboard.key.saving": "保存中…",
|
|
915
|
+
"onboard.soul.title": "个性化助手",
|
|
916
|
+
"onboard.soul.desc": "大约 30 秒,通过两个快速问答卡片完成设置。",
|
|
917
|
+
"onboard.soul.btn.start": "开始 →",
|
|
918
|
+
"onboard.soul.btn.skip": "稍后再说",
|
|
919
|
+
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
|
|
923
|
+
// ── 会话信息栏 / 模型切换器 测速 ──
|
|
924
|
+
"sib.bench.btn": "测速",
|
|
925
|
+
"sib.bench.tooltip": "测试所有已配置模型的响应延迟",
|
|
926
|
+
"sib.bench.running": "测速中…",
|
|
927
|
+
"sib.bench.done": "用时 {{t}} 秒",
|
|
928
|
+
"sib.bench.failed": "失败:{{msg}}",
|
|
929
|
+
"sib.bench.latencyTooltip": "TTFT {{ttft}} · 测试于 {{time}}",
|
|
930
|
+
|
|
931
|
+
"onboard.welcome": "欢迎使用 {{name}}",
|
|
932
|
+
}
|
|
933
|
+
};
|
|
934
|
+
|
|
935
|
+
// ── State ──────────────────────────────────────────────────────────────────
|
|
936
|
+
let _lang = localStorage.getItem(STORAGE_KEY) || DEFAULT_LANG;
|
|
937
|
+
|
|
938
|
+
// ── Core functions ─────────────────────────────────────────────────────────
|
|
939
|
+
|
|
940
|
+
/** Return the current language code ("en" or "zh"). */
|
|
941
|
+
function lang() { return _lang; }
|
|
942
|
+
|
|
943
|
+
/** Set language, persist to localStorage, re-apply to DOM. */
|
|
944
|
+
function setLang(code) {
|
|
945
|
+
_lang = TRANSLATIONS[code] ? code : DEFAULT_LANG;
|
|
946
|
+
localStorage.setItem(STORAGE_KEY, _lang);
|
|
947
|
+
applyAll();
|
|
948
|
+
document.dispatchEvent(new CustomEvent("langchange", { detail: { lang: _lang } }));
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
/**
|
|
952
|
+
* Translate a key. Supports {{var}} interpolation.
|
|
953
|
+
* Falls back to English, then to the key itself.
|
|
954
|
+
*/
|
|
955
|
+
function t(key, vars = {}) {
|
|
956
|
+
const dict = TRANSLATIONS[_lang] || TRANSLATIONS[DEFAULT_LANG];
|
|
957
|
+
let str = dict[key] ?? TRANSLATIONS[DEFAULT_LANG][key] ?? key;
|
|
958
|
+
Object.entries(vars).forEach(([k, v]) => {
|
|
959
|
+
str = str.replaceAll(`{{${k}}}`, v);
|
|
960
|
+
});
|
|
961
|
+
return str;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/**
|
|
965
|
+
* Scan the DOM and apply translations to:
|
|
966
|
+
* data-i18n="key" → element.textContent
|
|
967
|
+
* data-i18n-placeholder="key" → element.placeholder
|
|
968
|
+
* data-i18n-title="key" → element.title
|
|
969
|
+
*/
|
|
970
|
+
function applyAll() {
|
|
971
|
+
document.querySelectorAll("[data-i18n]").forEach(el => {
|
|
972
|
+
const key = el.getAttribute("data-i18n");
|
|
973
|
+
const vars = _extractVars(el);
|
|
974
|
+
el.textContent = t(key, vars);
|
|
975
|
+
});
|
|
976
|
+
document.querySelectorAll("[data-i18n-placeholder]").forEach(el => {
|
|
977
|
+
const key = el.getAttribute("data-i18n-placeholder");
|
|
978
|
+
const vars = _extractVars(el);
|
|
979
|
+
let ph = t(key, vars);
|
|
980
|
+
// On mobile: strip the parenthetical hint so placeholder doesn't wrap
|
|
981
|
+
if (window.innerWidth <= 768) {
|
|
982
|
+
ph = ph.replace(/\s*[\((].*[\))]/, "").trim();
|
|
983
|
+
}
|
|
984
|
+
el.placeholder = ph;
|
|
985
|
+
});
|
|
986
|
+
document.querySelectorAll("[data-i18n-title]").forEach(el => {
|
|
987
|
+
const key = el.getAttribute("data-i18n-title");
|
|
988
|
+
const vars = _extractVars(el);
|
|
989
|
+
el.title = t(key, vars);
|
|
990
|
+
});
|
|
991
|
+
|
|
992
|
+
// Update <html lang=""> attribute
|
|
993
|
+
document.documentElement.lang = _lang;
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/** Read data-i18n-vars="brand=Foo;n=3" into an object. */
|
|
997
|
+
function _extractVars(el) {
|
|
998
|
+
const raw = el.getAttribute("data-i18n-vars");
|
|
999
|
+
if (!raw) return {};
|
|
1000
|
+
return Object.fromEntries(
|
|
1001
|
+
raw.split(";").map(pair => pair.split("=").map(s => s.trim()))
|
|
1002
|
+
);
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// ── Public API ─────────────────────────────────────────────────────────────
|
|
1006
|
+
return { lang, setLang, t, applyAll };
|
|
1007
|
+
})();
|
|
1008
|
+
|
|
1009
|
+
// ── Thinking Verbs for Progress Animation ──────────────────────────────────
|
|
1010
|
+
//
|
|
1011
|
+
// The primary verb ("Thinking" / "思考中") is chosen 90% of the time inside
|
|
1012
|
+
// getRandomThinkingVerb(). The lists below are ONLY the 10% flavor variants —
|
|
1013
|
+
// do not include the primary verb here, and do not rely on duplicates for
|
|
1014
|
+
// weighting (probability is controlled in code, not data).
|
|
1015
|
+
const THINKING_VERBS = {
|
|
1016
|
+
en: [
|
|
1017
|
+
"Cogitating",
|
|
1018
|
+
"Pondering",
|
|
1019
|
+
"Ruminating",
|
|
1020
|
+
"Deliberating",
|
|
1021
|
+
"Contemplating",
|
|
1022
|
+
"Flibbertigibbeting",
|
|
1023
|
+
"Percolating",
|
|
1024
|
+
"Noodling",
|
|
1025
|
+
"Brewing",
|
|
1026
|
+
"Marinating",
|
|
1027
|
+
"Stewing",
|
|
1028
|
+
"Mulling",
|
|
1029
|
+
"Processing",
|
|
1030
|
+
"Computing",
|
|
1031
|
+
"Calculating",
|
|
1032
|
+
"Analyzing",
|
|
1033
|
+
"Synthesizing",
|
|
1034
|
+
"Ideating",
|
|
1035
|
+
"Brainstorming",
|
|
1036
|
+
"Reasoning"
|
|
1037
|
+
],
|
|
1038
|
+
zh: [
|
|
1039
|
+
"推理中",
|
|
1040
|
+
"深度思考中",
|
|
1041
|
+
"分析中",
|
|
1042
|
+
"解析中",
|
|
1043
|
+
"拆解中",
|
|
1044
|
+
"推演中",
|
|
1045
|
+
"梳理中",
|
|
1046
|
+
"归纳中",
|
|
1047
|
+
"演算中",
|
|
1048
|
+
"验证中",
|
|
1049
|
+
"权衡中",
|
|
1050
|
+
"构思中",
|
|
1051
|
+
"酝酿中",
|
|
1052
|
+
"思忖中",
|
|
1053
|
+
"琢磨中"
|
|
1054
|
+
]
|
|
1055
|
+
};
|
|
1056
|
+
|
|
1057
|
+
// Get a random thinking verb based on current language.
|
|
1058
|
+
//
|
|
1059
|
+
// Behavior: 90% of the time return the primary verb ("思考中" / "Thinking"),
|
|
1060
|
+
// 10% of the time pick a random variant from the list for a bit of flavor.
|
|
1061
|
+
// The primary is intentionally kept outside the list so tuning the probability
|
|
1062
|
+
// is a single-number change here, independent of the list contents.
|
|
1063
|
+
function getRandomThinkingVerb() {
|
|
1064
|
+
const lang = I18n.lang();
|
|
1065
|
+
const primary = lang === "zh" ? "思考中" : "Thinking";
|
|
1066
|
+
|
|
1067
|
+
// 90% primary, 10% variant
|
|
1068
|
+
if (Math.random() < 0.9) return primary;
|
|
1069
|
+
|
|
1070
|
+
const verbs = THINKING_VERBS[lang] || THINKING_VERBS.en;
|
|
1071
|
+
if (!verbs || verbs.length === 0) return primary;
|
|
1072
|
+
return verbs[Math.floor(Math.random() * verbs.length)];
|
|
1073
|
+
}
|