@songsid/agend 2.3.1 → 2.3.2-beta.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.
Files changed (160) hide show
  1. package/dist/authority/authority-state.d.ts +4 -0
  2. package/dist/authority/authority-state.js +16 -10
  3. package/dist/authority/authority-state.js.map +1 -1
  4. package/dist/authority/session-authorizations.d.ts +7 -1
  5. package/dist/authority/session-authorizations.js +6 -4
  6. package/dist/authority/session-authorizations.js.map +1 -1
  7. package/dist/authority/web-authority.d.ts +19 -6
  8. package/dist/authority/web-authority.js +22 -8
  9. package/dist/authority/web-authority.js.map +1 -1
  10. package/dist/channel/adapters/discord.d.ts +2 -0
  11. package/dist/channel/adapters/discord.js +33 -3
  12. package/dist/channel/adapters/discord.js.map +1 -1
  13. package/dist/channel/mcp-tools.js +5 -5
  14. package/dist/channel/mcp-tools.js.map +1 -1
  15. package/dist/channel/types.d.ts +11 -0
  16. package/dist/config-validator.js +40 -3
  17. package/dist/config-validator.js.map +1 -1
  18. package/dist/daemon.d.ts +34 -3
  19. package/dist/daemon.js +227 -46
  20. package/dist/daemon.js.map +1 -1
  21. package/dist/delivery-outbox.d.ts +12 -1
  22. package/dist/delivery-outbox.js +67 -15
  23. package/dist/delivery-outbox.js.map +1 -1
  24. package/dist/doctor.d.ts +3 -0
  25. package/dist/doctor.js +9 -0
  26. package/dist/doctor.js.map +1 -1
  27. package/dist/event-log.d.ts +5 -0
  28. package/dist/event-log.js +13 -0
  29. package/dist/event-log.js.map +1 -1
  30. package/dist/fleet-manager.d.ts +140 -0
  31. package/dist/fleet-manager.js +414 -29
  32. package/dist/fleet-manager.js.map +1 -1
  33. package/dist/fleet-process-handlers.d.ts +1 -0
  34. package/dist/fleet-process-handlers.js +9 -1
  35. package/dist/fleet-process-handlers.js.map +1 -1
  36. package/dist/general-knowledge/skills/web-appearance/SKILL.canvas-worker-off.md +4 -4
  37. package/dist/general-knowledge/skills/web-appearance/SKILL.md +7 -7
  38. package/dist/general-knowledge/skills/web-dashboard/SKILL.canvas-worker-off.md +113 -55
  39. package/dist/general-knowledge/skills/web-dashboard/SKILL.md +114 -56
  40. package/dist/guest-seen-people.d.ts +38 -0
  41. package/dist/guest-seen-people.js +78 -0
  42. package/dist/guest-seen-people.js.map +1 -0
  43. package/dist/instance-config-impact.js +4 -1
  44. package/dist/instance-config-impact.js.map +1 -1
  45. package/dist/instance-lifecycle.d.ts +1 -0
  46. package/dist/instance-lifecycle.js +16 -1
  47. package/dist/instance-lifecycle.js.map +1 -1
  48. package/dist/locale.js +38 -10
  49. package/dist/locale.js.map +1 -1
  50. package/dist/mac-auto-restore.d.ts +117 -0
  51. package/dist/mac-auto-restore.js +294 -0
  52. package/dist/mac-auto-restore.js.map +1 -0
  53. package/dist/outbound-schemas.d.ts +2 -0
  54. package/dist/outbound-schemas.js +2 -0
  55. package/dist/outbound-schemas.js.map +1 -1
  56. package/dist/public-web-gateway.js +9 -1
  57. package/dist/public-web-gateway.js.map +1 -1
  58. package/dist/settings-api.d.ts +26 -0
  59. package/dist/settings-api.js +107 -1
  60. package/dist/settings-api.js.map +1 -1
  61. package/dist/settings-change.js +37 -3
  62. package/dist/settings-change.js.map +1 -1
  63. package/dist/settings-effect.js +5 -2
  64. package/dist/settings-effect.js.map +1 -1
  65. package/dist/start-attempt.d.ts +9 -5
  66. package/dist/start-attempt.js +27 -8
  67. package/dist/start-attempt.js.map +1 -1
  68. package/dist/start-failure-chat.d.ts +4 -0
  69. package/dist/start-failure-chat.js +23 -6
  70. package/dist/start-failure-chat.js.map +1 -1
  71. package/dist/start-failure-notice.d.ts +4 -0
  72. package/dist/start-failure-notice.js +8 -0
  73. package/dist/start-failure-notice.js.map +1 -1
  74. package/dist/start-failure.d.ts +25 -0
  75. package/dist/start-failure.js +75 -2
  76. package/dist/start-failure.js.map +1 -1
  77. package/dist/turn-reply-guard.d.ts +25 -0
  78. package/dist/turn-reply-guard.js +111 -12
  79. package/dist/turn-reply-guard.js.map +1 -1
  80. package/dist/types.d.ts +18 -1
  81. package/dist/ui/backend-signin.js +5 -2
  82. package/dist/ui/chat-ambient.js +1 -1
  83. package/dist/ui/chat-effects.js +4 -4
  84. package/dist/ui/chat-render.js +5 -2
  85. package/dist/ui/chat-strings.js +2 -2
  86. package/dist/ui/chat-thread.js +2 -2
  87. package/dist/ui/first-run.js +2 -2
  88. package/dist/ui/fleet-canvas-view.js +114 -0
  89. package/dist/ui/fleet-canvas.js +15 -77
  90. package/dist/ui/fleet-office-editor.js +80 -5
  91. package/dist/ui/fleet-office-layout.js +197 -0
  92. package/dist/ui/fleet-office-model.js +6 -3
  93. package/dist/ui/fleet-office-overview.js +167 -0
  94. package/dist/ui/fleet-office-pack.d.ts +39 -0
  95. package/dist/ui/fleet-office-pack.js +240 -29
  96. package/dist/ui/fleet-office-skin.js +140 -29
  97. package/dist/ui/fleet-office-store.js +84 -5
  98. package/dist/ui/fleet-office-view.js +154 -0
  99. package/dist/ui/fleet-office-zones.js +95 -33
  100. package/dist/ui/fleet-office.js +779 -140
  101. package/dist/ui/fleet-usage.js +7 -6
  102. package/dist/ui/panel-chat.js +1 -1
  103. package/dist/ui/panel-details.js +2 -2
  104. package/dist/ui/panel-fleet.js +11 -77
  105. package/dist/ui/panel-log.js +2 -2
  106. package/dist/ui/panel-settings.js +578 -163
  107. package/dist/ui/search-dialog.js +26 -7
  108. package/dist/ui/settings-appearance.js +82 -29
  109. package/dist/ui/settings-apply.js +42 -7
  110. package/dist/ui/settings-dialogs.js +68 -22
  111. package/dist/ui/settings-draft.js +51 -0
  112. package/dist/ui/settings-guests.js +244 -78
  113. package/dist/ui/settings-learn.js +2 -2
  114. package/dist/ui/settings-model.js +2 -0
  115. package/dist/ui/settings-registry.js +142 -0
  116. package/dist/ui/settings-strings.js +102 -44
  117. package/dist/ui/settings-web-authority.js +34 -23
  118. package/dist/ui/shared/app-i18n.js +14 -0
  119. package/dist/ui/shared/app-nav.js +10 -5
  120. package/dist/ui/shared/app-prefs.js +80 -2
  121. package/dist/ui/shared/app-route.js +39 -5
  122. package/dist/ui/shared/app-shell.js +59 -4
  123. package/dist/ui/shared/app-stream.js +2 -1
  124. package/dist/ui/shared/app.css +254 -17
  125. package/dist/ui/shared/app.js +3 -0
  126. package/dist/ui/shared/effect-stock-trust.js +1 -1
  127. package/dist/ui/shared/identity-color.js +4 -4
  128. package/dist/ui/shared/signin.js +2 -2
  129. package/dist/ui/shared/ui-dialog.js +6 -1
  130. package/dist/ui/shared/ui-icons.js +2 -0
  131. package/dist/ui/shared/web-authorize.js +13 -12
  132. package/dist/web-api.d.ts +8 -2
  133. package/dist/web-api.js +160 -5
  134. package/dist/web-api.js.map +1 -1
  135. package/dist/web-auth.js +7 -1
  136. package/dist/web-auth.js.map +1 -1
  137. package/dist/web-experimental.d.ts +1 -1
  138. package/dist/web-experimental.js +1 -1
  139. package/dist/web-experimental.js.map +1 -1
  140. package/dist/web-mod-agent.js +2 -2
  141. package/dist/web-mod-agent.js.map +1 -1
  142. package/dist/web-office-skins.d.ts +108 -0
  143. package/dist/web-office-skins.js +298 -0
  144. package/dist/web-office-skins.js.map +1 -0
  145. package/dist/web-office-store.d.ts +8 -2
  146. package/dist/web-office-store.js +37 -7
  147. package/dist/web-office-store.js.map +1 -1
  148. package/dist/web-settings-patch.d.ts +6 -0
  149. package/dist/web-settings-patch.js +61 -4
  150. package/dist/web-settings-patch.js.map +1 -1
  151. package/dist/web-shell-routes.d.ts +4 -2
  152. package/dist/web-shell-routes.js +17 -7
  153. package/dist/web-shell-routes.js.map +1 -1
  154. package/dist/working-recovery.d.ts +104 -0
  155. package/dist/working-recovery.js +263 -0
  156. package/dist/working-recovery.js.map +1 -0
  157. package/dist/working-state-journal.d.ts +3 -1
  158. package/dist/working-state-journal.js +15 -2
  159. package/dist/working-state-journal.js.map +1 -1
  160. package/package.json +1 -1
@@ -0,0 +1,142 @@
1
+ // #2347 §6: the settings registry — one entry per setting, for Settings' search and the Ctrl K "Settings" group: where it
2
+ // is (its section, and the element to bring into view), what it is called in both languages (a settings string key,
3
+ // `labelKey`, or `label`), its config key, and the words people search with (synonyms, in both languages). A test
4
+ // mounts every section and checks each field drawn has an entry, and each entry's element is drawn in its section.
5
+ import { lang, tIn } from "/assets/app-i18n.js";
6
+ import { sectionPath } from "/assets/app-route.js";
7
+ import { navigate } from "/assets/app-nav.js";
8
+ import "./settings-strings.js";
9
+ import "./chat-strings.js";
10
+ import { GUESTS_SETTINGS } from "./settings-guests.js";
11
+
12
+ const L = (en, zh) => ({ en, "zh-TW": zh });
13
+ /** [id, section, target, labelKey | label, config key, words en, words zh] */
14
+ const ROWS = [
15
+ // You · Preferences
16
+ ["profile.name", "preferences", "#profile-name", "settings.profileTitle", null, ["name", "display name", "who agents see", "profile"], ["名字", "名稱", "顯示名稱", "個人資料"]],
17
+ ["prefs.theme", "preferences", "#pref-theme", "app.theme", null, ["theme", "dark", "light", "dark mode", "colour scheme"], ["主題", "深色", "淺色", "外觀"]],
18
+ ["prefs.lang", "preferences", "#pref-lang", "app.language", null, ["language", "dashboard language", "english", "chinese", "locale"], ["語言", "介面語言", "中文", "英文"]],
19
+ ["prefs.names", "preferences", "#pref-names", "app.names", null, ["names", "nickname", "real name", "instance name", "display"], ["名稱", "暱稱", "實名"]],
20
+ ["prefs.previews", "preferences", "#pref-previews", "chat.previews", null, ["html preview", "preview", "iframe"], ["預覽", "HTML 預覽"]],
21
+ ["prefs.tour", "preferences", "#tourBtn", "chat.tour", null, ["tour", "help", "walkthrough", "guide"], ["導覽", "說明", "教學"]],
22
+ ["device.motion", "preferences", "#fx-follow-reduced-motion", "settings.themesFollowMotion", null, ["reduced motion", "animation", "effects", "accessibility"], ["減少動態", "動畫", "特效", "無障礙"]],
23
+ ["device.css-off", "preferences", "#css-off-here", "settings.cssDeviceOff", null, ["custom css", "css off", "this device", "safe"], ["自訂 CSS", "關閉 CSS", "這個裝置"]],
24
+ // You · Look
25
+ ["look.themes", "look", "#fx-show-themes", "settings.themesShow", "fx.show", ["agent themes", "themes", "effects", "widgets"], ["主題", "agent 的主題", "特效", "小工具"]],
26
+ ["look.colours", "look", ".s-colors", "settings.colorTitle", "color.show", ["identity colour", "color", "colour", "turn off colours"], ["識別色", "顏色", "關閉顏色"]],
27
+ ["look.cards", "look", ".s-card-size", "settings.cardSizeTitle", "card.size", ["identity card", "card size", "portrait", "banner"], ["身分卡", "卡片大小"]],
28
+ ["look.widget", "look", ".s-widget", "settings.widgetTitle", "widget.sidebar", ["sidebar widget", "widget", "json"], ["側邊欄小工具", "小工具"]],
29
+ ["look.css", "look", ".s-owner-css", "settings.cssTitle", null, ["custom css", "stylesheet", "style", "css"], ["自訂 CSS", "樣式表", "樣式"]],
30
+ ["look.mods", "look", ".s-mods", "settings.modsTitle", null, ["mod", "mods", "import", "add-on", "agendmod"], ["mod", "匯入", "擴充"]],
31
+ ["look.effects", "look", ".s-effects", null, null, ["effects", "canvas", "ambient", "petals", "click stars"], ["特效", "效果", "花瓣", "氛圍"], L("Effects", "效果")],
32
+ ["look.restore", "look", ".s-restore", "settings.restoreTitle", null, ["restore defaults", "reset", "default"], ["還原預設值", "重設", "預設"]],
33
+ // Fleet · Agents
34
+ ["agents.new", "agents", "#newAgentBtn", "settings.newAgent", null, ["new agent", "create", "add agent", "instance"], ["新增 agent", "建立", "新 agent"]],
35
+ ["agents.provider-keys", "agents", ".s-provider-keys", "settings.providerKeys", "web.provider_secrets", ["api key", "provider", "openai", "anthropic", "token", "secret"], ["API 金鑰", "金鑰", "供應商", "token"]],
36
+ // Fleet · Agent defaults
37
+ ["defaults.locale", "agent-defaults", "#g-locale", "settings.language", "defaults.locale", ["language", "bot language", "reply language", "locale"], ["語言", "回覆語言", "bot 語言"]],
38
+ ["defaults.backend", "agent-defaults", "#g-be", "settings.defaultBackend", "defaults.backend", ["backend", "cli", "claude", "codex", "kiro"], ["後端", "CLI"]],
39
+ ["defaults.model", "agent-defaults", "#g-model", "settings.defaultModel", "defaults.model", ["model", "opus", "sonnet", "gpt"], ["模型"]],
40
+ ["defaults.auto-pause", "agent-defaults", "#g-auto", "settings.autoPause", "defaults.auto_pause_after", ["auto pause", "idle", "sleep", "minutes"], ["自動暫停", "閒置", "休眠"]],
41
+ ["defaults.tool-progress", "agent-defaults", "#g-tp", "settings.toolProgress", "defaults.tool_progress", ["tool progress", "verbose", "steps"], ["工具進度", "詳細"]],
42
+ ["defaults.visibility", "agent-defaults", "#g-vis", "settings.crossInstanceVisibility", "defaults.cross_instance_visibility", ["visibility", "bot to bot", "cross instance", "messages"], ["可見性", "bot 之間", "跨 instance"]],
43
+ ["defaults.reply-guard", "agent-defaults", "#g-reply", "settings.replyCompletionGuard", "defaults.reply_completion_guard", ["delivered reply", "reply guard", "require reply"], ["送達回覆", "回覆保護"]],
44
+ ["defaults.tool-set", "agent-defaults", "#g-ts", "settings.toolSet", "defaults.tool_set", ["tool set", "tools", "mcp"], ["工具組", "工具"]],
45
+ ["defaults.dashboard", "agent-defaults", "#g-dash", "settings.dashboardAccess", "defaults.dashboard", ["dashboard access", "dashboard features", "permissions", "appearance tools", "task board", "web settings"], ["Dashboard 權限", "權限", "外觀", "任務看板", "網頁設定"]],
46
+ ["defaults.log-level", "agent-defaults", "#g-ll", "settings.logLevel", "defaults.log_level", ["log level", "debug", "logging"], ["記錄層級", "除錯", "日誌"]],
47
+ ["defaults.agent-mode", "agent-defaults", "#g-am", "settings.agentMode", "defaults.agent_mode", ["agent mode", "mcp", "cli"], ["agent 模式"]],
48
+ ["defaults.hang-on", "agent-defaults", "#g-hang-on", "settings.hangEnabled", "defaults.hang_detector.enabled", ["hang detector", "stuck", "frozen"], ["卡住偵測", "卡住", "當機"]],
49
+ ["defaults.hang-timeout", "agent-defaults", "#g-hang", "settings.hangTimeout", "defaults.hang_detector.timeout_minutes", ["hang timeout", "stuck", "minutes"], ["卡住逾時", "逾時"]],
50
+ ["defaults.concurrency", "agent-defaults", "#g-conc", "settings.concurrency", "startup.concurrency", ["startup", "concurrency", "parallel", "spawn"], ["啟動", "並行"]],
51
+ ["defaults.project-roots", "agent-defaults", "#g-roots", "settings.projectRootsTitle", "project_roots", ["project roots", "folders", "directory", "where agents work", "working directory"], ["專案資料夾", "資料夾", "目錄", "工作目錄"]],
52
+ ["defaults.stagger", "agent-defaults", "#g-stag", "settings.staggerDelay", "startup.stagger_delay_ms", ["startup", "stagger", "delay"], ["啟動", "間隔", "延遲"]],
53
+ // Fleet · Chat & connections
54
+ ["chat.new-connection", "chat", "#newBotBtn", "settings.newBot", "channels", ["new connection", "bot", "telegram", "discord", "bot token", "token"], ["新增連線", "bot", "Telegram", "Discord", "bot token", "token"]],
55
+ ["chat.web-echo", "chat", "#webEchoToChannel", "settings.webEcho", "web.echo_to_channel", ["web echo", "mirror", "copy to chat", "echo"], ["網頁轉發", "轉發", "同步到聊天"]],
56
+ ["chat.classic-rooms", "chat", "#classicbot", "settings.classicChannels", null, ["classicbot", "rooms", "channels"], ["ClassicBot", "房間", "頻道"]],
57
+ ["chat.classic-backend", "chat", "#g-cbe", "settings.classicBackend", "classic_defaults.backend", ["classicbot backend", "backend"], ["ClassicBot 後端", "後端"]],
58
+ ["chat.classic-tool-progress", "chat", "#g-ctp", "settings.toolProgress", "classic_defaults.tool_progress", ["classicbot tool progress", "tool progress"], ["ClassicBot 工具進度", "工具進度"]],
59
+ ["chat.classic-reply-guard", "chat", "#g-creply", "settings.replyCompletionGuard", "classic_defaults.reply_completion_guard", ["classicbot delivered reply", "reply guard"], ["ClassicBot 送達回覆"]],
60
+ ["chat.classic-admins", "chat", "#g-admins", "settings.classicAdmins", "classic.admin_users", ["classicbot admins", "who can use classicbot", "admin"], ["ClassicBot 管理員", "誰可以使用 ClassicBot", "管理員"]],
61
+ ["chat.classic-guilds", "chat", "#g-guilds", "settings.allowedGuilds", "classic.allowed_guilds", ["discord server", "guild", "allowed servers"], ["Discord 伺服器", "伺服器"]],
62
+ // Fleet · Web dashboard
63
+ ["dash.log-tab", "web-dashboard", "#webLogTab", "settings.webLogTab", "web.log_tab", ["log tab", "steps", "log"], ["Log 分頁", "紀錄", "步驟"]],
64
+ ["dash.usage-public", "web-dashboard", "#webUsagePublic", "settings.webUsagePublic", "web.usage_report_on_public_link", ["usage", "public link", "cost", "tokens"], ["用量", "公開連結", "費用"]],
65
+ ["dash.app-icon", "web-dashboard", ".s-app-icon", "settings.appIconTitle", null, ["app icon", "favicon", "home screen", "icon"], ["App 圖示", "圖示", "主畫面"]],
66
+ ["dash.card-limits", "web-dashboard", ".s-card-limits", "settings.cardLimitsTitle", "web.appearance", ["upload limits", "portrait", "banner", "card limits"], ["上傳限制", "身分卡上傳限制"]],
67
+ ["dash.canvas-worker", "web-dashboard", ".s-experimental-effects", "experimentalEffects.title", "web.experimental.canvas_worker", ["canvas worker", "experimental", "effects"], ["Canvas Worker", "實驗功能", "特效"]],
68
+ // Fleet · Access & security
69
+ ["access.session-absolute", "access", "#webSessionAbsolute", "settings.sessionAbsolute", "web.session.local.absolute_hours", ["session", "sign in", "hours", "expire", "logout"], ["session", "登入", "時數", "到期"]],
70
+ ["access.session-idle", "access", "#webSessionIdle", "settings.sessionIdle", "web.session.local.idle_hours", ["session", "idle", "unused", "hours"], ["session", "閒置", "時數"]],
71
+ ["access.terminal", "access", "#webTerminalEnabled", "settings.webTerminalEnabled", "web_terminal.enabled", ["browser terminal", "terminal", "login", "shell"], ["瀏覽器終端機", "終端機", "登入"]],
72
+ ["access.terminal-ttl", "access", "#webTerminalTtl", "settings.webTerminalTtl", "web_terminal.ttl_minutes", ["terminal minutes", "terminal", "ttl"], ["終端機", "分鐘"]],
73
+ ["access.public-link", "access", "#publicWebLink", "settings.publicLink", "web.public_link.allow_public", ["public link", "share", "tunnel", "cloudflare", "trycloudflare"], ["公開連結", "分享", "tunnel"]],
74
+ ["access.hostname", "access", "#publicWebHostname", "settings.namedHostname", "web.public_link.hostname", ["fixed address", "domain", "hostname", "named tunnel", "https"], ["固定網址", "網域", "主機名稱", "具名 tunnel"]],
75
+ ["access.origin-port", "access", "#publicWebOriginPort", "settings.namedOriginPort", "web.public_link.origin_port", ["port", "origin port", "fixed address"], ["連接埠", "port", "固定網址"]],
76
+ ["access.public-ttl", "access", "#publicWebTtl", "settings.publicTtl", "web.public_link.ttl_minutes", ["public link minutes", "how long", "ttl", "no expiry", "expire"], ["公開連結", "分鐘", "多久", "不過期", "到期"]],
77
+ // Shown with a fixed hostname (a named tunnel), or while it is set.
78
+ ["access.public-auto-open", "access", "#publicAutoOpen", "settings.publicAutoOpen", "web.public_link.auto_open", ["reopen after restart", "auto open", "public link", "named link"], ["重新開啟", "自動開啟", "公開連結", "固定網域"]],
79
+ ["access.protocol", "access", "#publicWebProtocol", "settings.publicProtocol", "web.public_link.protocol", ["protocol", "http2", "quic", "https"], ["通訊協定", "協定"]],
80
+ ["access.cloudflare-token", "access", "#publicTunnelToken", "settings.namedToken", "web.public_link.tunnel_token_env", ["cloudflare token", "tunnel token", "token", "fixed address", "secret"], ["Cloudflare token", "tunnel token", "token", "固定網址", "金鑰"]],
81
+ ["access.authority", "access", "#vaEnabled", "settings.vaEnabled", "web.verified_authority.enabled", ["web authority", "verified", "authorize"], ["網頁授權", "驗證", "授權"]],
82
+ ["access.authority-loopback", "access", "#vaLoopbackOnly", "settings.vaLoopbackOnly", "web.verified_authority.loopback_only", ["only this computer", "loopback", "authorize"], ["只有這台電腦", "授權"]],
83
+ // #2453: shown with a fixed hostname (a named tunnel), or while it is on; its label names the hostname, so its own words here.
84
+ ["access.authority-named-link", "access", "#vaNamedLink", null, "web.verified_authority.named_link", ["named link", "my named link", "authorize", "fixed hostname"], ["固定網域", "授權", "named link"], L("Also over my named link", "也允許透過我的固定網域")],
85
+ ["access.authority-quick-link", "access", "#vaQuickLink", null, "web.verified_authority.quick_link", ["temporary public link", "quick link", "quick tunnel", "authorize", "trycloudflare"], ["臨時公開連結", "授權", "quick tunnel"], L("Also over the temporary public link", "也允許透過臨時公開連結")],
86
+ ["access.authority-hours", "access", "#vaHours", null, "web.verified_authority.max_session_hours", ["authorization hours", "how long", "authority"], ["授權時數", "多久"], L("How long a web authorization lasts", "網頁授權持續多久")],
87
+ ["access.authority-revoke", "access", "#vaRevoke", "settings.vaRevoke", null, ["revoke", "sign out", "authority"], ["撤銷", "登出", "授權"]],
88
+ // Fleet · Advanced
89
+ ["advanced.fleet-yaml", "advanced", ".s-dev", null, null, ["fleet.yaml", "yaml", "json", "raw", "edit config"], ["fleet.yaml", "YAML", "設定檔"], L("fleet.yaml (YAML / JSON)", "fleet.yaml(YAML / JSON)")],
90
+ ["advanced.read-only", "advanced", ".s-web-ro", "settings.webReadOnlyTitle", null, ["allowed hosts", "view access", "preview port", "read only", "web settings"], ["allowed hosts", "唯讀", "網頁設定"]],
91
+ ];
92
+
93
+ export const SETTINGS_REGISTRY = Object.freeze([
94
+ ...ROWS.map(([id, section, target, labelKey, key, en, zh, label]) => Object.freeze({ id, section, target, labelKey, label: label || null, key, words: { en, "zh-TW": zh } })),
95
+ // dev-claude2's Guests section (#2348): its entries, brought to the same shape (the card itself is the target).
96
+ ...GUESTS_SETTINGS.map((g) => Object.freeze({ id: g.id, section: g.section, target: g.id === "guests.enabled" ? "#guestsEnabled" : g.id === "guests.chat" ? "#guestsChat" : "#guests",
97
+ labelKey: null, label: g.label, key: g.key || null, words: g.words })),
98
+ ]);
99
+
100
+ /** An entry's name in a language. */
101
+ export function settingLabel(entry, language = lang()) {
102
+ return entry.label ? entry.label[language] || entry.label.en : tIn(language, entry.labelKey);
103
+ }
104
+
105
+ const fold = (s) => String(s || "").toLowerCase().normalize("NFKC");
106
+ /**
107
+ * Entries matching `query`: every word in it is found in the entry's name (either language), its config key, or its
108
+ * words (either language). Ranked: a name that starts with it, then one that contains it, then a config key, then a word.
109
+ */
110
+ export function searchSettings(query) {
111
+ const terms = fold(query).split(/\s+/).filter(Boolean);
112
+ if (!terms.length) return [];
113
+ const scored = [];
114
+ for (const entry of SETTINGS_REGISTRY) {
115
+ const names = [settingLabel(entry, "en"), settingLabel(entry, "zh-TW")].map(fold);
116
+ const keys = fold(entry.key || "");
117
+ const words = [...(entry.words.en || []), ...(entry.words["zh-TW"] || [])].map(fold);
118
+ let score = 0, all = true;
119
+ for (const term of terms) {
120
+ const s = names.some((n) => n.startsWith(term)) ? 4 : names.some((n) => n.includes(term)) ? 3 : keys.includes(term) ? 2 : words.some((w) => w.includes(term)) ? 1 : 0;
121
+ if (!s) { all = false; break; }
122
+ score += s;
123
+ }
124
+ if (all) scored.push({ entry, score });
125
+ }
126
+ return scored.sort((a, b) => b.score - a.score).map((s) => s.entry);
127
+ }
128
+
129
+ // The setting a search result opened, brought into view once its section is drawn (the panel asks for it).
130
+ let pending = null;
131
+ /** Go to a setting: its section, then (once drawn) the setting itself, focused and flashed. */
132
+ export function goToSetting(entry) {
133
+ pending = entry ? entry.target : null;
134
+ navigate(sectionPath(entry.section));
135
+ }
136
+ /** Go to a section and, once it is drawn, to one element in it (a field the bar says to fix). */
137
+ export function goToTarget(section, target) {
138
+ pending = target || null;
139
+ navigate(sectionPath(section));
140
+ }
141
+ /** The element a search result asked for, once (null: none). */
142
+ export function takePendingSetting() { const p = pending; pending = null; return p; }
@@ -60,6 +60,11 @@ register("settings", {
60
60
  autoPause: "Auto-pause after",
61
61
  minutes: "minutes",
62
62
  inheritDefault: "Inherit from defaults",
63
+ // #2347 §10: the value in effect, and where it comes from.
64
+ defaultMark: "default", inEffect: "In effect: {0}", inheritedValue: "Inherited: {0}",
65
+ changeInDefaults: "change in Agent defaults", changeInClassic: "change in ClassicBot defaults",
66
+ cappedBySession: "capped by the session length", hoursValue: "{0} h", minutesValue: "{0} min", valueOn: "on", valueOff: "off", valueNone: "none",
67
+ concurrencyAuto: "automatic, 2–10 by free memory and CPU cores", inEffectShort: "in effect: {0}", cappedByTotal: "capped by upload_max_total_mb",
63
68
  statusEmojis: "Status emojis",
64
69
  statusEmojisInstance: "This agent's status emojis (override the connection's)",
65
70
  statusEmojisChannel: "Status emojis for this connection's bots",
@@ -162,7 +167,7 @@ register("settings", {
162
167
  applyClose: "Close",
163
168
  settingsButton: "Settings",
164
169
  connRetryNow: "Retry now", connRetryQueued: "Connection retry requested.", connRetryFailed: "Could not retry this connection. Check its status and try again.",
165
- modalDone: "Stage change",
170
+ modalDone: "Done",
166
171
  wizardButton: "Setup wizard",
167
172
  wizardTitle: "Set up AgEnD",
168
173
  wizardStep: "Step {0} of {1}",
@@ -209,6 +214,7 @@ register("settings", {
209
214
  deleteBot: "Delete this bot",
210
215
  noAllowedUsers: "no allowed users",
211
216
  searchAll: "Search agents, bots, channels…",
217
+ searchSettings: "Search settings — token, 語言, session…", searchNone: "No setting matches.", searchFoot: "↑↓ move · Enter go there · Esc close · also under Ctrl K → Settings",
212
218
  accessMovedHint: "Who may use the bot is set on the connection itself — open Settings on \"{0}\" under Connections.",
213
219
  applyRestartNeeded: "Saved — restart AgEnD to apply",
214
220
  applyNoChange: "no change needed",
@@ -226,13 +232,15 @@ register("settings", {
226
232
  signatureMismatch: "fleet.yaml and the running configuration disagree on: {0}. Restarting will not clear this — check daemon.log first.",
227
233
  applyStillWorking: "Still restarting ({0}s) — AgEnD is still working; this page keeps checking.",
228
234
  applyLostJob: "Lost track of this apply (the fleet may have restarted). Reload the page to see the current state.",
229
- changesPending: "{0} change(s) not applied",
235
+ changesPending: "{0} unsaved change(s)",
236
+ fixToSave: "Fix {0} field(s) to save", fixToSaveIn: "Fix {0} field(s) in {1} to save",
230
237
  impactNow: "Immediately",
231
238
  impactAgent: "Restart this Agent",
232
239
  impactFleet: "Restart AgEnD",
233
- queued: "Queued: {0}",
240
+ queued: "Not saved yet: {0} — Save below",
234
241
  applyFailed: "Apply failed",
235
242
  changesApplied: "Changes applied. AgEnD is reconciling affected Agents.",
243
+ youPrefs: "Your preferences", youSaved: "Saved.", youSaveFailed: "Some of your preferences were not saved — try again.", youDeviceChoice: "This device: {0}",
236
244
  reviewChanges: "Review changes",
237
245
  backendUnavailable: "{0} (removed — choose another backend)",
238
246
  backendNotInstalled: "not installed", backendNotSignedIn: "not signed in (use /login)", backendTooOld: "needs {0} or newer", backendUnchecked: "not checked yet",
@@ -254,7 +262,7 @@ register("settings", {
254
262
  concurrencyWarning: "May exceed CPU capacity on smaller hosts",
255
263
  staggerRange: "Must be between 0 and 30000",
256
264
  staggerWarning: "Very low values can cause startup spikes",
257
- sec_device: "Preferences", syncedTitle: "Synced across your devices", syncedLead: "Changes here apply on every device where you are signed in.",
265
+ "sec_preferences": "Preferences", syncedTitle: "Synced across your devices", syncedLead: "Changes here apply on every device where you are signed in.",
258
266
  profileTitle: "Your name",
259
267
  profileLeadBound: "Agents see your web messages as the Discord or Telegram account your sign-in code was sent to: its id, and its name unless you choose another here. It follows you to every device you sign in on. Agents do your ordinary requests as you; a release, anything destructive, spending, secrets or passing your authority on needs this browser authorized, or your confirm in Discord or Telegram.",
260
268
  profileLeadUnbound: "This browser was not signed in with a code sent to your Discord or Telegram account, so agents see your web messages as \"web-user\" (or the name you set here). Sign in with a code from /web to be recognised as your account.",
@@ -263,10 +271,9 @@ register("settings", {
263
271
  syncedPublicLink: "On the public link these are read-only: a change here stays in this browser.",
264
272
  deviceTitle: "This device only", deviceLead: "The tour, text size, view fit, the sidebar shown or hidden, panel widths and desktop notifications stay on each device.",
265
273
  sec_agents: "Agents",
266
- sec_bots: "Connections",
267
- sec_classic: "ClassicBot",
268
- sec_general: "General",
269
- sec_advanced: "Developer",
274
+ "sec_agent-defaults": "Agent defaults", sec_chat: "Chat & connections", "sec_web-dashboard": "Web dashboard", sec_access: "Access & security",
275
+ sec_advanced: "Advanced", sec_look: "Look", grp_you: "You", grp_fleet: "Fleet",
276
+ classicDefaultsTitle: "ClassicBot defaults", publicLinkTitle: "Public link & fixed address", webDashboardTitle: "Dashboard features", webSettingsLabel: "Web settings",
270
277
  stRunning: "Running",
271
278
  stPaused: "Paused",
272
279
  stCrashed: "Crashed",
@@ -288,6 +295,8 @@ register("settings", {
288
295
  deleteAgentMenu: "Delete agent",
289
296
  deleteAgentLabel: "Delete {0}",
290
297
  updateAgent: "Update {0}",
298
+ projectRootsTitle: "Project folders", projectRootsHint: "New agents may only work inside these folders (empty: anywhere). Checked when an agent is created.",
299
+ projectRootsAnywhere: "any folder",
291
300
  updateDefaults: "Update agent defaults",
292
301
  updateClassicDefaults: "Update ClassicBot defaults and access",
293
302
  updateAccess: "Update {0} access",
@@ -321,10 +330,8 @@ register("settings", {
321
330
  keyRollbackFailed: "Rollback failed",
322
331
  accessTitle: "Access",
323
332
  webChat: "Web chat",
324
- sec_web: "Web",
325
333
  // #1629 r4 §3: Settings → Appearance (owner CSS).
326
- sec_appearance: "Web appearance",
327
- groupLook: "Look", groupLayout: "Your layout", groupCss: "Styles you write", groupMods: "Add-ons", groupAdvanced: "Advanced", learnMore: "Learn more: {0}",
334
+ motionTitle: "Effects on this device", groupLook: "Look", groupLayout: "Your layout", groupCss: "Styles you write", groupMods: "Add-ons", groupAdvanced: "Advanced", learnMore: "Learn more: {0}",
328
335
  colorTitle: "Identity colours", colorLead: "One agent's colour: its ⋯ menu → Colour…",
329
336
  colorPlaces: "Where colours show", colorSample: "Sample agent", colorOff: "Turn off colours",
330
337
  colorOffLead: "Colours people picked are kept.",
@@ -394,7 +401,7 @@ register("settings", {
394
401
  modInstalled: "Installed {0}.",
395
402
  modFailed: "Not done: {0}",
396
403
  idLine: "ID: {0}",
397
- modCanvasWorkerOff: "Not done: this mod has Canvas Worker effects, an experimental feature. Turn it on in Settings → Web appearance first.",
404
+ modCanvasWorkerOff: "Not done: this mod has Canvas Worker effects, an experimental feature. Turn it on in Settings → Web dashboard first.",
398
405
  modDownload: "Download",
399
406
  modUninstall: "Uninstall",
400
407
  modUninstallConfirm: "Uninstall {0}? Its effects leave your library unless something still uses them. What it applied stays.",
@@ -498,7 +505,6 @@ register("settings", {
498
505
  sessionIdle: "Sign out after unused for, hours (1–720)",
499
506
  sessionRange: "Must be a number of hours from 1 to 720",
500
507
  sessionIdleOver: "Must not exceed the session length",
501
- defaultHours: "{0} (default)",
502
508
  webTerminalTitle: "Browser terminal",
503
509
  webTerminalHint: "The token-gated terminal /login opens to sign a CLI in. Off: /login refuses. Applies to the next /login.",
504
510
  webTerminalEnabled: "Allow the browser terminal",
@@ -516,14 +522,36 @@ register("settings", {
516
522
  guestNarrow: "Narrow", guestNotReachable: "(no longer reachable)", guestReachesNothing: "This account reaches no agent from chat right now, so there is nothing to narrow.", guestNarrowLift: "Remove narrowing", guestNarrowHint: "Tick what this guest may still reach. Narrowing only takes away (it applies at once); widening or removing it waits for a fleet admin's confirmation.",
517
523
  guestSignOut: "Sign out", guestSignOutTitle: "Sign out this guest?", guestSignOutConfirm: "{0}'s guest sessions end now, their sign-in code stops working and their browsers are forgotten. They can sign in again with /web while guest sign-in is on.",
518
524
  guestSignedOut: "{0} is signed out.", guestSignedOutNotDurable: "{0} is signed out for now, but it could not be saved: a restart may bring their sessions back.", guestSignOutFailed: "That did not work — try again.",
525
+ // #2348: explicit grants.
526
+ grantsHint: "Choose who may sign in as a guest and which agents each of them sees. A guest sees a granted agent's chat as its channel showed it — other people's messages there too, never web-only ones. Granting waits for a fleet admin's OK in General; taking away applies at once.",
527
+ grantsLegacy: "Guests now reach what their chat access gives them. Saving grants switches to explicit access: only the people below, only their ticked agents.",
528
+ grantsConvert: "Start from today's guests", grantsWithAccess: "People with access", grantsNoneYet: "No one has guest access yet.",
529
+ grantsAdd: "Add a person", grantsSearch: "Search people who have written to your agents", grantsNoPeople: "No one matches. A person must have written to an agent first.",
530
+ grantsChoose: "Choose", grantsChosen: "Chosen", grantsMaySee: "{0} may see:", grantsWroteHere: "wrote here", grantsWroteTo: "Wrote to: {0}",
531
+ grantsLastSeen: "last seen {0}", grantsRecent: "Recent changes", grantsRecentNone: "No change to anyone's access yet.", grantsAuditDirect: "applied at once", grantsAuditConfirmed: "confirmed in General", grantsAuditEnded: "{0} session(s) ended", grantsAuditCodeSent: "sign-in code sent", grantsAuditCodeNot: "sign-in code not sent ({0})", grantsAuditDmFailed: "the DM did not go through", grantsAuditWait: "asked again within a minute", grantsAuditAdminLimit: "the admin's limit of codes was reached",
532
+ grantsEditAgents: "Edit agents", grantsRemove: "Remove access", grantsUndoRemove: "Keep access",
533
+ grantsWillBeRemoved: "Access ends when you save.", grantsNew: "New — granted when you save", grantsNoAgents: "Tick at least one agent, or remove this person.",
534
+ grantsSend: "Send sign-in code", grantsSendAgain: "Send again in {0}", grantsSendSaveFirst: "Save first: a code goes only to saved access.",
535
+ grantsSent: "Code sent {0} · expires {1}", grantsSentPublic: "It works on the open public link too.", grantsSending: "Sending…",
536
+ grantsSignedIn: "Signed in · {0} device(s)", grantsNotSignedIn: "Not signed in",
537
+ grantsDmFailed: "Couldn't DM {0}: {1}", grantsDmFailedTg: "Couldn't DM {0}: they haven't started the bot. Send them this link: {1}",
538
+ grantsDmFailedDiscord: "Couldn't DM {0}: their Discord privacy settings block messages from this server.",
539
+ grantsWait: "One code a minute per person — try again shortly.", grantsAdminLimit: "You've sent many codes; try again in a few minutes.",
540
+ grantsCodeFailed: "The code was not sent: {0}",
541
+ codeGuestsOff: "guest sign-in is off", codeAdmin: "a fleet admin signs in as an admin", codeNothing: "nothing is granted to this person yet — save their access first",
542
+ codeStarting: "AgEnD is starting or this connection is not running", codePaused: "guest sign-in is paused for a few minutes (too many wrong codes)",
543
+ codeBusy: "too many guest codes are waiting to be used — try again in a few minutes", codeRevoked: "you are no longer authorized", grantsWaiting: "Waiting for a fleet admin's OK in General.", grantsSaveFailed: "Not saved: {0}",
544
+ grantsPublicLinkNote: "If they aren't on this network, open the public link first, then send the code.",
519
545
  vaTitle: "Web authority", vaReview: "Review web authority changes",
520
- vaHint: "Whether a signed-in fleet admin's web messages carry their own account's authority, recorded in each message's delivery receipt. A session signed in with a code sent privately to that account, on the dashboard reached directly, is authorized once from Discord or Telegram; the public link and guests never are. Agents do an admin's ordinary web requests either way; a release, anything destructive, spending, secrets or passing authority on needs this.",
546
+ vaHint: "Whether a signed-in fleet admin's web messages carry their own account's authority, recorded in each message's delivery receipt. A session signed in with a code sent privately to that account, on the dashboard reached directly, is authorized once from Discord or Telegram. Guests never are; over a public link, only while its option below is on. Agents do an admin's ordinary web requests either way; a release, anything destructive, spending, secrets or passing authority on needs this.",
521
547
  vaLoadFailed: "Web authority could not be loaded.",
522
548
  vaEnabled: "Web messages carry authority", vaEnabledHint: "On by default: a session carries authority only once its account confirms it from Discord or Telegram. Off: no web message carries authority, and any already given reads as none at once; authority given before it was turned off never comes back.",
523
549
  vaStuckOff: "Web authority is off for now: its state could not be saved on this computer (see the fleet log). It comes back on by itself once it can be.",
524
550
  vaLoopbackOnly: "Only this computer can authorize", vaLoopbackOnlyHint: "On: only a browser on this computer qualifies, not one on your network or tailnet, and authority already given from elsewhere reads as none. Turning it off again doesn't bring that back.",
525
- vaNamedLink: "Also over my named link ({0})", vaNamedLinkHint: "On: a browser signed in over your own named-tunnel hostname may be authorized too (the same Confirm in your DM). It is reached from the internet, and Cloudflare sees its traffic: turning this on is confirmed in a General or on this computer. Off applies at once, and every authorization given over it reads as none. A quick tunnel never qualifies.",
551
+ vaNamedLink: "Also over my named link ({0})", vaNamedLinkHint: "On: a browser signed in over your own named-tunnel hostname may be authorized too (the same Confirm in your DM). It is reached from the internet, and Cloudflare sees its traffic: turning this on is confirmed in a General or on this computer. Off applies at once, and every authorization given over it reads as none. The temporary public link has its own option below.",
526
552
  vaSessionNamed: "over your named link",
553
+ vaQuickLink: "Also over the temporary public link", vaQuickLinkHint: "On: a browser signed in over the temporary public link that /web opens may be authorized too (the same Confirm in your DM). That link is an address on the internet, served by Cloudflare's quick-tunnel service, which sees its traffic. Turning this on is confirmed in a General or on this computer, and ends every authorization given so far (each browser confirms again). Turning it off applies at once. An authorized browser's authority ends with the link.",
554
+ vaSessionQuick: "over the temporary public link",
527
555
  vaLanWarning: "The dashboard also answers to {0} (web.allowed_hosts). Anyone who reaches it there with a stolen sign-in could give authority in your name. Turn on \"Only this computer can authorize\" unless you trust everyone who can reach it.",
528
556
  vaHours: "An authorization lasts (hours, {0}–{1})", vaHoursRange: "Must be a number from 1 to 48",
529
557
  vaSessionsTitle: "Authorized sessions", vaSessionsNone: "No session is authorized now.", vaSessionUntil: "Authorized {0} · until {1}",
@@ -533,7 +561,6 @@ register("settings", {
533
561
  searchRetentionUnset: "not set (no age limit; 300,000-row cap)",
534
562
  searchRetentionZero: "0 (no age limit; 300,000-row cap)",
535
563
  webSearchHint: "Global search keeps entries with no age limit by default. The daily prune still caps the index at 300,000 rows (oldest first). Set web.search.retention_days in fleet.yaml (1–3650 days, or 0 for no age limit); it takes effect at the next fleet start.",
536
- notSet: "not set (default)",
537
564
  defaultsTitle: "Defaults",
538
565
  classicBackend: "ClassicBot default backend",
539
566
  whoUsesClassic: "Who can use ClassicBot",
@@ -541,7 +568,6 @@ register("settings", {
541
568
  guildIdPlaceholder: "guild id",
542
569
  tagPlaceholder: "tag",
543
570
  removeItem: "Remove {0}",
544
- inheritPlaceholder: "(inherit default)",
545
571
  zeroDisabled: "0 = off",
546
572
  optional: "optional",
547
573
  collabMode: "Collaboration mode",
@@ -574,10 +600,10 @@ register("settings", {
574
600
  rotateToken: "Rotate the {0} token",
575
601
  addBotLabel: "Add connection {0}",
576
602
  removeBotLabel: "Remove connection {0}",
577
- pendingRegion: "Changes not applied yet",
603
+ pendingRegion: "Unsaved changes",
578
604
  discard: "Discard",
579
- applyChanges: "Apply changes",
580
- discardOnLeave: "Discard {0} pending changes?",
605
+ applyChanges: "Save",
606
+ discardOnLeave: "Discard {0} unsaved change(s)?",
581
607
  applyBusyLocal: "An Apply is still running — wait for it to finish.",
582
608
  applyStepFailed: "Stopped at a change: {0}. The changes after it were not applied; they are staged again.",
583
609
  applyError_unsupported_sensitive_effect: "it changes a setting the confirmation cannot show safely, so nothing was changed",
@@ -601,8 +627,12 @@ register("settings", {
601
627
  copy: "Copy",
602
628
  devDownload: "Download fleet.yaml",
603
629
  devEditor: "fleet.yaml editor",
604
- devApply: "Apply & save",
605
- devApplyHint: "Writes these settings and applies them, like Apply changes.",
630
+ devApply: "Apply",
631
+ devApplyHint: "Adds this edit to the Save bar below: Save writes it, with any other unsaved change.",
632
+ devStaged: "In the Save bar: {0} change(s) to fleet.yaml. Save writes them, Discard drops them; edit and Apply again to replace them.",
633
+ devFormsUnsaved: "Save or discard the unsaved changes to agents, agent defaults or connections first: this editor writes the same settings.",
634
+ yamlUnsaved: "An unsaved fleet.yaml edit (Advanced) writes these settings. Save or discard it to edit them here.",
635
+ yamlOpen: "Open the editor",
606
636
  noChanges: "Nothing to change.",
607
637
  wizardCommitting: "Writing the configuration…",
608
638
  wizardPlatform: "Platform",
@@ -698,6 +728,10 @@ register("settings", {
698
728
  autoPause: "閒置後自動暫停",
699
729
  minutes: "分鐘",
700
730
  inheritDefault: "沿用全域預設值",
731
+ defaultMark: "預設", inEffect: "目前生效:{0}", inheritedValue: "沿用:{0}",
732
+ changeInDefaults: "到 Agent 預設值變更", changeInClassic: "到 ClassicBot 預設值變更",
733
+ cappedBySession: "受 session 時長限制", hoursValue: "{0} 小時", minutesValue: "{0} 分鐘", valueOn: "開", valueOff: "關", valueNone: "無",
734
+ concurrencyAuto: "自動,依可用記憶體與 CPU 核心數取 2–10", inEffectShort: "實際:{0}", cappedByTotal: "受 upload_max_total_mb 限制",
701
735
  detection: "偵測",
702
736
  startup: "啟動",
703
737
  backendSection: "後端",
@@ -775,7 +809,7 @@ register("settings", {
775
809
  applyClose: "關閉",
776
810
  settingsButton: "設定",
777
811
  connRetryNow: "立即重試", connRetryQueued: "已要求重新連線。", connRetryFailed: "無法重試此連線,請檢查狀態後再試。",
778
- modalDone: "加入待套用",
812
+ modalDone: "完成",
779
813
  wizardButton: "設定精靈",
780
814
  wizardTitle: "設定 AgEnD",
781
815
  wizardStep: "第 {0} 步,共 {1} 步",
@@ -822,6 +856,7 @@ register("settings", {
822
856
  deleteBot: "刪除這個機器人",
823
857
  noAllowedUsers: "沒有允許的使用者",
824
858
  searchAll: "搜尋 agent、機器人、頻道…",
859
+ searchSettings: "搜尋設定 —— token、語言、session…", searchNone: "沒有符合的設定。", searchFoot: "↑↓ 移動・Enter 前往・Esc 關閉・也可從 Ctrl K → 設定 找到",
825
860
  accessMovedHint: "誰可以使用 bot 是在連線本身設定 —— 請到「連線」開啟「{0}」的設定。",
826
861
  applyRestartNeeded: "已儲存 —— 需要重新啟動 AgEnD 才會生效",
827
862
  applyNoChange: "無需變更",
@@ -839,13 +874,15 @@ register("settings", {
839
874
  signatureMismatch: "fleet.yaml 與執行中的設定在這些項目上不一致:{0}。重新啟動無法解決,請先查看 daemon.log。",
840
875
  applyStillWorking: "仍在重啟中({0} 秒)—— AgEnD 還在處理,此頁面會持續確認。",
841
876
  applyLostJob: "已追蹤不到這次套用(AgEnD 可能重啟過)。請重新整理頁面查看目前狀態。",
842
- changesPending: "有 {0} 項變更尚未套用",
877
+ changesPending: "{0} 項變更未儲存",
878
+ fixToSave: "修正 {0} 個欄位後才能儲存", fixToSaveIn: "修正「{1}」的 {0} 個欄位後才能儲存",
843
879
  impactNow: "立即生效",
844
880
  impactAgent: "重新啟動此 Agent",
845
881
  impactFleet: "重新啟動 AgEnD",
846
- queued: "已加入待套用:{0}",
882
+ queued: "尚未儲存:{0} —— 請按下方的儲存",
847
883
  applyFailed: "套用失敗",
848
884
  changesApplied: "變更已套用,AgEnD 正在協調受影響的 Agent。",
885
+ youPrefs: "你的偏好設定", youSaved: "已儲存。", youSaveFailed: "部分偏好設定沒有儲存,請再試一次。", youDeviceChoice: "這個裝置:{0}",
849
886
  reviewChanges: "檢查變更",
850
887
  backendUnavailable: "{0}(已移除,請選擇其他 backend)",
851
888
  backendNotInstalled: "未安裝", backendNotSignedIn: "未登入(請用 /login)", backendTooOld: "需要 {0} 以上版本", backendUnchecked: "尚未檢查",
@@ -867,7 +904,7 @@ register("settings", {
867
904
  concurrencyWarning: "在較小的主機上可能超出 CPU 負荷",
868
905
  staggerRange: "必須介於 0 到 30000",
869
906
  staggerWarning: "數值太低可能造成啟動尖峰",
870
- sec_device: "偏好設定", syncedTitle: "在你所有的裝置同步", syncedLead: "這裡的變更會套用到你登入的每一台裝置。",
907
+ "sec_preferences": "偏好", syncedTitle: "在你所有的裝置同步", syncedLead: "這裡的變更會套用到你登入的每一台裝置。",
871
908
  profileTitle: "你的名字",
872
909
  profileLeadBound: "agent 會把你從網頁送出的訊息,認成收到登入驗證碼的那個 Discord 或 Telegram 帳號:用它的 id,名字也用它的,除非你在這裡另外取名。它會跟著你到每一台登入的裝置。一般的請求,agent 會當作是你本人提出的;發布、破壞性操作、花費、密鑰,或把你的授權交給別人,則要先授權這個瀏覽器,或在 Discord、Telegram 上確認。",
873
910
  profileLeadUnbound: "這個瀏覽器不是用私訊到你 Discord 或 Telegram 帳號的驗證碼登入的,所以 agent 會把你的網頁訊息看成「web-user」(或你在這裡設定的名字)。用 /web 的驗證碼登入,就能被認成你的帳號。",
@@ -876,10 +913,9 @@ register("settings", {
876
913
  syncedPublicLink: "公開連結只能讀取這些設定:在這裡變更只會留在這個瀏覽器。",
877
914
  deviceTitle: "只限這台裝置", deviceLead: "導覽、文字大小、視圖寬度、側欄顯示或隱藏、面板寬度與桌面通知,每台裝置各自保留。",
878
915
  sec_agents: "Agent",
879
- sec_bots: "連線",
880
- sec_classic: "ClassicBot",
881
- sec_general: "一般",
882
- sec_advanced: "開發者",
916
+ "sec_agent-defaults": "Agent 預設值", sec_chat: "聊天與連線", "sec_web-dashboard": "網頁儀表板", sec_access: "存取與安全",
917
+ sec_advanced: "進階", sec_look: "外觀", grp_you: "你自己", grp_fleet: "整個 Fleet",
918
+ classicDefaultsTitle: "ClassicBot 預設值", publicLinkTitle: "公開連結與固定網址", webDashboardTitle: "儀表板功能", webSettingsLabel: "網頁設定",
883
919
  stRunning: "執行中",
884
920
  stPaused: "已暫停",
885
921
  stCrashed: "已當掉",
@@ -901,6 +937,8 @@ register("settings", {
901
937
  deleteAgentMenu: "刪除 agent",
902
938
  deleteAgentLabel: "刪除 {0}",
903
939
  updateAgent: "更新 {0}",
940
+ projectRootsTitle: "專案資料夾", projectRootsHint: "新的 agent 只能在這些資料夾裡工作(留空:不限)。建立 agent 時檢查。",
941
+ projectRootsAnywhere: "不限",
904
942
  updateDefaults: "更新 agent 預設值",
905
943
  updateClassicDefaults: "更新 ClassicBot 預設值與存取",
906
944
  updateAccess: "更新 {0} 的存取",
@@ -934,9 +972,7 @@ register("settings", {
934
972
  keyRollbackFailed: "還原失敗",
935
973
  accessTitle: "存取",
936
974
  webChat: "網頁聊天",
937
- sec_web: "網頁",
938
- sec_appearance: "網頁外觀",
939
- groupLook: "外觀", groupLayout: "你的版面", groupCss: "自己寫的樣式", groupMods: "擴充", groupAdvanced: "進階", learnMore: "了解更多:{0}",
975
+ motionTitle: "這個裝置上的特效", groupLook: "外觀", groupLayout: "你的版面", groupCss: "自己寫的樣式", groupMods: "擴充", groupAdvanced: "進階", learnMore: "了解更多:{0}",
940
976
  colorTitle: "識別色", colorLead: "單一 agent 的顏色:⋯ 選單 → 顏色…",
941
977
  colorPlaces: "顏色顯示的位置", colorSample: "範例 agent", colorOff: "關閉顏色",
942
978
  colorOffLead: "已挑選的顏色會保留。",
@@ -1006,7 +1042,7 @@ register("settings", {
1006
1042
  modInstalled: "已安裝 {0}。",
1007
1043
  modFailed: "未完成:{0}",
1008
1044
  idLine: "ID:{0}",
1009
- modCanvasWorkerOff: "未完成:這個 mod 含有 Canvas Worker 效果,這是實驗性功能。請先到「設定 → 網頁外觀」開啟。",
1045
+ modCanvasWorkerOff: "未完成:這個 mod 含有 Canvas Worker 效果,這是實驗性功能。請先到「設定 → 網頁儀表板」開啟。",
1010
1046
  modDownload: "下載",
1011
1047
  modUninstall: "解除安裝",
1012
1048
  modUninstallConfirm: "要解除安裝 {0} 嗎?它的效果會離開你的效果庫,除非還有東西在使用。它已套用的外觀會保留。",
@@ -1110,7 +1146,6 @@ register("settings", {
1110
1146
  sessionIdle: "閒置多久後登出,小時(1–720)",
1111
1147
  sessionRange: "必須是 1 到 720 之間的小時數",
1112
1148
  sessionIdleOver: "不能超過 session 時長",
1113
- defaultHours: "{0}(預設)",
1114
1149
  webTerminalTitle: "瀏覽器終端機",
1115
1150
  webTerminalHint: "/login 用來登入 CLI 的 token 保護終端機。關閉時 /login 會拒絕。下一次 /login 起生效。",
1116
1151
  webTerminalEnabled: "允許瀏覽器終端機",
@@ -1128,14 +1163,35 @@ register("settings", {
1128
1163
  guestNarrow: "縮小範圍", guestNotReachable: "(已無法使用)", guestReachesNothing: "這個帳號目前在聊天中沒有能用的 agent,沒有可以縮小的範圍。", guestNarrowLift: "取消縮小", guestNarrowHint: "勾選這位訪客仍可使用的 agent。縮小只會拿走權限(立即生效);放寬或取消縮小需 fleet admin 確認。",
1129
1164
  guestSignOut: "登出", guestSignOutTitle: "登出這位訪客?", guestSignOutConfirm: "{0} 的訪客 session 會立即結束,登入碼失效,記住的瀏覽器也會被忘記。訪客登入開啟期間,他可以再傳 /web 登入。",
1130
1165
  guestSignedOut: "已登出 {0}。", guestSignedOutNotDurable: "已暫時登出 {0},但無法保存:重新啟動後他的 session 可能會恢復。", guestSignOutFailed: "沒有成功,請再試一次。",
1166
+ grantsHint: "選擇誰可以用訪客身分登入,以及每個人可以看到哪些 agent。訪客看到的是頻道上原本顯示的對話(包含頻道裡其他人的訊息),看不到只在網頁上的訊息。新增授權需 fleet 管理員在 General 同意;收回立即生效。",
1167
+ grantsLegacy: "目前訪客能看到的,取決於他們在聊天中的權限。儲存授權後改為明確授權:只有下列的人,只看得到勾選的 agent。",
1168
+ grantsConvert: "以目前的訪客為起點", grantsWithAccess: "有存取權的人", grantsNoneYet: "還沒有人有訪客存取權。",
1169
+ grantsAdd: "新增人員", grantsSearch: "搜尋曾傳訊息給你的 agent 的人", grantsNoPeople: "沒有符合的人。對方必須先傳過訊息給某個 agent。",
1170
+ grantsChoose: "選擇", grantsChosen: "已選擇", grantsMaySee: "{0} 可以看到:", grantsWroteHere: "傳過訊息", grantsWroteTo: "傳過訊息給:{0}",
1171
+ grantsLastSeen: "最後出現 {0}", grantsRecent: "最近的變更", grantsRecentNone: "還沒有人的存取權變更過。", grantsAuditDirect: "立即生效", grantsAuditConfirmed: "在 General 確認後生效", grantsAuditEnded: "結束了 {0} 個登入", grantsAuditCodeSent: "已寄出登入碼", grantsAuditCodeNot: "登入碼未寄出({0})", grantsAuditDmFailed: "私訊沒有送達", grantsAuditWait: "一分鐘內重複要求", grantsAuditAdminLimit: "已達管理員的登入碼上限",
1172
+ grantsEditAgents: "編輯 agent", grantsRemove: "移除存取權", grantsUndoRemove: "保留存取權",
1173
+ grantsWillBeRemoved: "儲存後存取權就會結束。", grantsNew: "新增 —— 儲存後授權", grantsNoAgents: "至少勾選一個 agent,或移除這個人。",
1174
+ grantsSend: "傳送登入碼", grantsSendAgain: "{0} 後可再傳", grantsSendSaveFirst: "請先儲存:登入碼只會傳給已儲存的授權。",
1175
+ grantsSent: "{0} 已傳送 · {1} 到期", grantsSentPublic: "也可以用在目前開啟的公開連結上。", grantsSending: "傳送中…",
1176
+ grantsSignedIn: "已登入 · {0} 個裝置", grantsNotSignedIn: "未登入",
1177
+ grantsDmFailed: "無法私訊 {0}:{1}", grantsDmFailedTg: "無法私訊 {0}:對方還沒有啟動 bot。請把這個連結傳給對方:{1}",
1178
+ grantsDmFailedDiscord: "無法私訊 {0}:對方的 Discord 隱私設定擋住了這個伺服器的私訊。",
1179
+ grantsWait: "每人每分鐘只能傳一次登入碼,請稍後再試。", grantsAdminLimit: "你已經傳了很多登入碼,請幾分鐘後再試。",
1180
+ grantsCodeFailed: "沒有傳出登入碼:{0}",
1181
+ codeGuestsOff: "訪客登入未開啟", codeAdmin: "fleet 管理員以管理員身分登入", codeNothing: "這個人還沒有任何授權——請先儲存對方的存取權限",
1182
+ codeStarting: "AgEnD 正在啟動,或這個連線沒有在執行", codePaused: "訪客登入暫停幾分鐘(錯誤的登入碼太多)",
1183
+ codeBusy: "目前有太多訪客登入碼還沒被使用,請過幾分鐘再試", codeRevoked: "你已不再被授權", grantsWaiting: "等待 fleet 管理員在 General 同意。", grantsSaveFailed: "沒有儲存:{0}",
1184
+ grantsPublicLinkNote: "如果對方不在這個網路上,請先開啟公開連結,再傳送登入碼。",
1131
1185
  vaTitle: "網頁授權", vaReview: "檢視網頁授權變更",
1132
- vaHint: "已登入的 fleet 管理者從網頁送出的訊息,是否帶有他本人帳號的授權,記錄在每則訊息的送達收據中。用私下傳給該帳號的登入碼、透過直接連線的 dashboard 登入的 session,要在 Discord 或 Telegram 上授權一次;公開連結與訪客一律不行。一般的網頁請求,agent 本來就會照做;發布、破壞性操作、花費、密鑰,或把授權交給別人,則需要它。",
1186
+ vaHint: "已登入的 fleet 管理者從網頁送出的訊息,是否帶有他本人帳號的授權,記錄在每則訊息的送達收據中。用私下傳給該帳號的登入碼、透過直接連線的 dashboard 登入的 session,要在 Discord 或 Telegram 上授權一次;訪客一律不行;公開連結只在下方對應的選項開啟時可以。一般的網頁請求,agent 本來就會照做;發布、破壞性操作、花費、密鑰,或把授權交給別人,則需要它。",
1133
1187
  vaLoadFailed: "無法載入網頁授權。",
1134
1188
  vaEnabled: "網頁訊息帶有授權", vaEnabledHint: "預設開啟:session 要等它的帳號在 Discord 或 Telegram 上確認後才帶有授權。關閉:網頁訊息都不帶授權,已給出的授權立即視為無;關閉前給出的授權不會恢復。",
1135
1189
  vaStuckOff: "網頁授權目前是關閉的:它的狀態無法存到這台電腦上(請看 fleet 紀錄)。可以存入後會自動恢復。",
1136
1190
  vaLoopbackOnly: "只有這台電腦可以授權", vaLoopbackOnlyHint: "開啟:只有這台電腦上的瀏覽器符合,網路或 tailnet 上的不算,之前從其他地方給出的授權視為無。再關掉也不會讓那些授權恢復。",
1137
- vaNamedLink: "也允許透過我的固定網域({0})", vaNamedLinkHint: "開啟:透過你自己的 named tunnel 固定網域登入的瀏覽器也能被授權(一樣要在私訊按「確認」)。它可從網際網路連到,Cloudflare 也看得到流量:開啟需在 General 或這台電腦上確認。關閉立即生效,透過它給出的授權都視為無。Quick tunnel 一律不行。",
1191
+ vaNamedLink: "也允許透過我的固定網域({0})", vaNamedLinkHint: "開啟:透過你自己的 named tunnel 固定網域登入的瀏覽器也能被授權(一樣要在私訊按「確認」)。它可從網際網路連到,Cloudflare 也看得到流量:開啟需在 General 或這台電腦上確認。關閉立即生效,透過它給出的授權都視為無。臨時公開連結另有下方的選項。",
1138
1192
  vaSessionNamed: "透過你的固定網域",
1193
+ vaQuickLink: "也允許透過臨時公開連結", vaQuickLinkHint: "開啟:透過 /web 開出的臨時公開連結登入的瀏覽器也能被授權(一樣要在私訊按「確認」)。這個連結是網際網路上的位址,由 Cloudflare 的 quick tunnel 服務轉送,Cloudflare 看得到流量。開啟需在 General 或這台電腦上確認,並會結束到目前為止給出的所有授權(每個瀏覽器都要重新確認);關閉立即生效。已授權的瀏覽器在連結結束時一併失去授權。",
1194
+ vaSessionQuick: "透過臨時公開連結",
1139
1195
  vaLanWarning: "dashboard 也接受 {0} 的連線(web.allowed_hosts)。任何人只要從那裡連上、又拿到被盜的登入,就能以你的名義給出授權。除非你信任所有能連到那裡的人,否則請開啟「只有這台電腦可以授權」。",
1140
1196
  vaHours: "一次授權的有效期(小時,{0}–{1})", vaHoursRange: "必須是 1 到 48 之間的數字",
1141
1197
  vaSessionsTitle: "已授權的 session", vaSessionsNone: "目前沒有已授權的 session。", vaSessionUntil: "{0} 授權 · 到 {1}",
@@ -1145,7 +1201,6 @@ register("settings", {
1145
1201
  searchRetentionUnset: "未設定(不限天數;上限 30 萬筆)",
1146
1202
  searchRetentionZero: "0(不限天數;上限 30 萬筆)",
1147
1203
  webSearchHint: "全域搜尋預設不限天數。每日清理仍會把索引上限維持在 30 萬筆(先刪最舊的)。在 fleet.yaml 設定 web.search.retention_days(1–3650 天,或 0 代表不限天數),下次啟動 fleet 後生效。",
1148
- notSet: "未設定(預設)",
1149
1204
  defaultsTitle: "預設值",
1150
1205
  classicBackend: "ClassicBot 預設 backend",
1151
1206
  whoUsesClassic: "誰可以使用 ClassicBot",
@@ -1153,7 +1208,6 @@ register("settings", {
1153
1208
  guildIdPlaceholder: "伺服器 id",
1154
1209
  tagPlaceholder: "標籤",
1155
1210
  removeItem: "移除 {0}",
1156
- inheritPlaceholder: "(沿用預設)",
1157
1211
  zeroDisabled: "0 = 關閉",
1158
1212
  optional: "選填",
1159
1213
  collabMode: "協作模式",
@@ -1186,10 +1240,10 @@ register("settings", {
1186
1240
  rotateToken: "更換 {0} token",
1187
1241
  addBotLabel: "新增連線 {0}",
1188
1242
  removeBotLabel: "移除連線 {0}",
1189
- pendingRegion: "尚未套用的變更",
1243
+ pendingRegion: "未儲存的變更",
1190
1244
  discard: "捨棄",
1191
- applyChanges: "套用變更",
1192
- discardOnLeave: "要捨棄 {0} 項尚未套用的變更嗎?",
1245
+ applyChanges: "儲存",
1246
+ discardOnLeave: "要捨棄 {0} 項未儲存的變更嗎?",
1193
1247
  applyBusyLocal: "還有一次套用在進行中——請等它完成。",
1194
1248
  applyStepFailed: "在某項變更停下:{0}。之後的變更沒有套用,已重新暫存。",
1195
1249
  applyError_unsupported_sensitive_effect: "它改到的設定無法在確認中安全顯示,所以什麼都沒有改",
@@ -1213,8 +1267,12 @@ register("settings", {
1213
1267
  copy: "複製",
1214
1268
  devDownload: "下載 fleet.yaml",
1215
1269
  devEditor: "fleet.yaml 編輯器",
1216
- devApply: "套用並儲存",
1217
- devApplyHint: "寫入這些設定並套用,和「套用變更」相同。",
1270
+ devApply: "套用",
1271
+ devApplyHint: "把這次編輯加入下方的儲存列:按「儲存」時和其他未儲存的變更一起寫入。",
1272
+ devStaged: "已加入儲存列:fleet.yaml 的 {0} 項變更。按「儲存」寫入,按「捨棄」放棄;修改後再按「套用」會取代它們。",
1273
+ devFormsUnsaved: "請先儲存或捨棄 Agent、Agent 預設值或連線中未儲存的變更:這個編輯器會寫入相同的設定。",
1274
+ yamlUnsaved: "有一份未儲存的 fleet.yaml 編輯(進階)會寫入這些設定。請先儲存或捨棄它,才能在這裡修改。",
1275
+ yamlOpen: "開啟編輯器",
1218
1276
  noChanges: "沒有需要變更的內容。",
1219
1277
  wizardCommitting: "正在寫入設定…",
1220
1278
  wizardPlatform: "平台",