{
  "installHint": {
    "cta": "Add to Home Screen",
    "title": "Use Avibe like an app",
    "body": "Add it to your Home Screen so the keyboard stops covering the input, with no browser bars and a more native feel.",
    "step1": "Tap the Share button at the bottom",
    "step2": "Choose “Add to Home Screen”",
    "dismiss": "Collapse"
  },
  "common": {
    "back": "Back",
    "continue": "Continue",
    "save": "Save",
    "skip": "Skip",
    "edit": "Edit",
    "cancel": "Cancel",
    "loading": "Loading...",
    "saving": "Saving...",
    "saved": "Saved",
    "saveFailed": "Save failed",
    "enabled": "Enabled",
    "enable": "Enable",
    "disable": "Disable",
    "disabled": "Disabled",
    "default": "Default",
    "inherit": "Inherit",
    "running": "Running",
    "stopped": "Stopped",
    "unknown": "Unknown",
    "online": "Online",
    "offline": "Offline",
    "public": "Public",
    "private": "Private",
    "notSet": "Not set",
    "notLinked": "Not linked",
    "found": "Found",
    "notFound": "Not Found",
    "notChecked": "Not checked",
    "missing": "Missing",
    "detect": "Detect",
    "detectAll": "Detect all",
    "refresh": "Refresh",
    "start": "Start",
    "stop": "Stop",
    "restart": "Restart",
    "viewDetails": "View details",
    "editSetup": "Open Setup Wizard",
    "manageChannels": "Manage groups",
    "viewLogs": "View logs",
    "saveAndRestart": "Save & Restart",
    "close": "Close",
    "submit": "Submit",
    "submitting": "Submitting…",
    "copy": "Copy",
    "copyFailed": "Copy failed, please copy it manually",
    "remove": "Remove",
    "removing": "Removing…",
    "delete": "Delete",
    "previous": "Previous",
    "next": "Next",
    "relative": {
      "justNow": "just now",
      "minutesAgo": "{{count}}m ago",
      "hoursAgo": "{{count}}h ago",
      "daysAgo": "{{count}}d ago"
    },
    "test": "Test",
    "testing": "Testing…",
    "themeSystem": "System theme",
    "themeLight": "Light theme",
    "themeDark": "Dark theme",
    "themeToggleHint": "Click to change theme",
    "step": "Step",
    "proxyUrl": "Proxy URL (optional)",
    "proxyUrlHint": "SOCKS5, SOCKS4, HTTP or HTTPS proxy. Leave empty to fall back to system SOCKS proxy detection or direct connection.",
    "proxyUrlCollapsedHint": "(blank → system proxy if set, else direct)"
  },
  "nav": {
    "dashboard": "Dashboard",
    "channels": "Groups",
    "users": "Direct Messages",
    "showPages": "Show Pages",
    "settings": "Settings",
    "remoteAccess": "Remote Access",
    "doctor": "Doctor",
    "inbox": "Inbox",
    "projects": "Projects",
    "capabilities": "Capabilities",
    "more": "More",
    "workbench": "Workbench"
  },
  "more": {
    "title": "More",
    "controlPanel": "Control Panel",
    "controlPanelDesc": "Channels · Users · Show Pages · Settings · Logs",
    "appearance": "Appearance",
    "connection": "Connection",
    "host": "Local address"
  },
  "projects": {
    "title": "Projects",
    "empty": "No projects yet",
    "newProject": "New project",
    "noSessions": "No sessions",
    "sessions": "{{count}} sessions",
    "loadMore": "Load more",
    "loadFailed": "Couldn't load — tap to retry"
  },
  "newSession": {
    "title": "New session",
    "project": "Project",
    "newProject": "New",
    "placeholder": "Describe what you want the agent to do…",
    "loadError": "Couldn't load projects — close and reopen to retry.",
    "createFailed": "Couldn't start the session. Please try again.",
    "agent": "Agent",
    "defaultAgent": "Default agent",
    "defaultAgentNamed": "Default · {{name}}"
  },
  "showPages": {
    "title": "Show Pages",
    "subtitle": "Every agent session has a Show Page. Make it public, keep it private, or take it offline.",
    "searchPlaceholder": "Search by title or session…",
    "allPages": "All pages",
    "sortedRecent": "Sorted by most recent",
    "filterAria": "Filter by visibility",
    "filter": { "online": "Online", "private": "Private", "public": "Public", "offline": "Offline" },
    "status": { "private": "Private", "public": "Public", "offline": "Offline" },
    "col": { "session": "Session", "visibility": "Visibility", "link": "Live link", "updated": "Updated" },
    "empty": "No Show Pages yet. They appear here once an agent session creates one.",
    "emptyFiltered": "No Show Pages match this filter.",
    "visibilityLabel": "Visibility",
    "visibilityOffline": "Offline",
    "liveLink": "Live link",
    "offlineNoLink": "This page is offline — bring it back with the control above to get a live link.",
    "copy": "Copy",
    "copied": "Copied",
    "open": "Open",
    "shareLink": "Share link",
    "rotate": "Rotate link",
    "rotateHint": "Generates a new link and disables the current one.",
    "cloudOff": "Avibe Cloud is off — this link only opens on this device.",
    "connectCloud": "Connect Avibe Cloud",
    "details": "Details",
    "detail": { "session": "Session ID", "workspace": "Workspace", "created": "Created", "updated": "Last updated" },
    "toast": { "updated": "Show Page updated", "rotated": "Share link rotated" }
  },
  "settings": {
    "tabs": {
      "service": "Service",
      "platforms": "Platforms",
      "backends": "Backends",
      "dependencies": "Dependencies",
      "messaging": "Messaging",
      "diagnostics": "Diagnostics",
      "serviceRoot": "Settings"
    },
    "serviceTitle": "Service",
    "serviceSubtitle": "Manage runtime status, console server details, and remote access from one place.",
    "logFileLabel": "Log file",
    "serviceRuntimeTitle": "Runtime control",
    "serviceRuntimeSubtitle": "Start, stop, and restart the local Avibe service while checking the live process state.",
    "statusNow": "Current state",
    "consoleServerTitle": "Console server",
    "consoleServerHint": "Saving these values restarts only the Web UI server.",
    "consoleServerRedirecting": "UI server moved. Redirecting to {{origin}}...",
    "consoleServerRelocated": "UI server now listens on {{origin}}. Open this URL to continue.",
    "serviceNotesTitle": "Operational notes",
    "serviceNotesSubtitle": "Keep the local service healthy before moving on to platform and routing work.",
    "serviceNote1": "Remote access is now part of Service because it changes how this machine exposes the local admin UI.",
    "serviceNote2": "Host and port changes restart only the UI server, while service control buttons affect the main Python runtime.",
    "serviceNote3": "Use Diagnostics for doctor checks and Live logs when you need detailed troubleshooting evidence.",
    "platformsTitle": "Platforms",
    "platformsSubtitle": "Configure which messaging platforms are connected and how each one is enabled.",
    "backendsTitle": "Backends",
    "backendsSubtitle": "Manage agent backends, default routing, and local CLI availability.",
    "dependenciesTitle": "Dependencies",
    "dependenciesSubtitle": "Local runtimes that Avibe installs and keeps up to date automatically.",
    "dependencies": {
      "autoBanner": "Avibe installs and updates these for you. Re-check, repair, or update manually below.",
      "recheckAll": "Re-check all",
      "required": "Required",
      "statusReady": "Ready",
      "statusDetected": "Detected",
      "statusMissing": "Not installed",
      "install": "Install",
      "reinstall": "Reinstall",
      "repair": "Repair",
      "installing": "Installing…",
      "installed": "{{name}} is ready.",
      "installFailed": "Install failed.",
      "backendsTitle": "Agent backends",
      "backendsDetail": "Claude · OpenCode · Codex — managed in the Backends tab.",
      "manageBackends": "Manage in Backends",
      "items": {
        "askill": { "label": "askill", "detail": "Agent Skills runtime — powers the Skills page." },
        "show-runtime": { "label": "Show Page runtime", "detail": "Renders visual Show Pages on your machine." },
        "node": { "label": "Node.js", "detail": "Shared prerequisite for the runtimes above." }
      }
    },
    "backends": {
      "routingTitle": "Default routing",
      "routingHint": "Pick the backend that powers new conversations by default. Per-group overrides are configured on the Groups page.",
      "defaultLabel": "Default",
      "defaultBadge": "Default",
      "configure": "Configure",
      "cliPathHint": "Avibe runs this command for every request. Use an absolute path if the binary is not on $PATH.",
      "opencodeTitle": "OpenCode provider",
      "opencodeSubtitle": "Detect or install the OpenCode CLI and apply the permission profile that lets it skip approval prompts.",
      "opencodeDescription": "Multi-provider open agent · CLI binary detection + permission profile",
      "claudeTitle": "Claude Code provider",
      "claudeSubtitle": "Detect or install the Claude Code CLI. Sign in or supply an API key from the CLI itself.",
      "claudeDescription": "Anthropic agent · sign in with Claude or supply an API key",
      "codexDescription": "OpenAI agent · ChatGPT login or OPENAI_API_KEY",
      "openProviderPage": "Configure provider",
      "providerOauth": "OAuth (default)",
      "providerApiKey": "API key",
      "codexTitle": "Codex provider",
      "codexSubtitle": "Switch between ChatGPT login and OpenAI API key, and point Codex at a custom endpoint when needed.",
      "codexBackToBackends": "Back to backends",
      "codexAuthModeLabel": "Authentication mode",
      "codexAuthModeOauth": "Sign in with ChatGPT",
      "codexAuthModeOauthHint": "Use a ChatGPT account to authorize Codex. Avibe stops managing the API key while this is selected.",
      "codexAuthModeApiKey": "OpenAI API key",
      "codexAuthModeApiKeyHint": "Codex will call the OpenAI-compatible endpoint with the key below. Switch to ChatGPT login if you prefer not to manage a key.",
      "codexApiKeyLabel": "API key",
      "codexApiKeyPlaceholder": "sk-...",
      "codexApiKeyConfigured": "A key of length {{length}} is currently stored.",
      "codexApiKeyMissing": "No API key stored yet.",
      "codexBaseUrlLabel": "Base URL (optional)",
      "codexBaseUrlPlaceholder": "https://api.openai.com/v1",
      "codexBaseUrlHint": "Leave empty to use OpenAI's default endpoint. Compatible relays (e.g. Azure OpenAI, OpenRouter) accept their own URL here.",
      "codexBaseUrlReset": "Reset to default",
      "codexHasChatgptTokens": "Codex has cached ChatGPT credentials from a previous sign-in.",
      "codexOauthSignedIn": "Codex is signed in via ChatGPT.",
      "codexOauthPanelTitle": "Sign in with your ChatGPT account",
      "codexOauthPanelSubtitle": "Open the device URL below, enter the code, and finish login in your browser. Codex will detect completion automatically.",
      "codexSignInButton": "Sign in with ChatGPT",
      "codexDeviceCodeLabel": "Device code",
      "codexDeviceInstructions": "Open the URL above, paste the device code, and complete sign-in in your browser. This page updates automatically when Codex receives the callback.",
      "codexCredentialsStoreKeyringWarn": "Codex is currently set to store credentials in the OS keychain ({{store}}). Saving here will switch it to file storage so Avibe can manage the API key directly.",
      "codexAuthModeUncertain": "Codex is set to store credentials in the OS keychain ({{store}}), so the current auth state cannot be read here. Choose a mode below and save — Avibe will switch Codex to file storage so future reads stay accurate.",
      "codexInfoHint": "Saving here writes `~/.codex/auth.json` and `~/.codex/config.toml`, then restarts the persistent app-server so the next request uses the new settings.",
      "codexSave": "Save and restart Codex",
      "codexSaving": "Saving…",
      "codexSaveSuccess": "Codex auth saved",
      "codexSaveFailed": "Could not save Codex auth",
      "claudeAuthModeLabel": "Authentication mode",
      "claudeAuthModeOauth": "Sign in with Claude",
      "claudeAuthModeOauthHint": "Use your Anthropic account to authorize Claude Code. Avibe stops managing the API key while this is selected.",
      "claudeAuthModeApiKey": "Anthropic API key",
      "claudeAuthModeApiKeyHint": "Saving updates Claude Code's own `settings.json` env block so the CLI uses this key directly.",
      "claudeOauthSignedIn": "Claude is signed in.",
      "claudeOauthPanelTitle": "Sign in with your Anthropic account",
      "claudeOauthPanelSubtitle": "Open the authorization URL below, approve access, then paste the callback code Anthropic shows you.",
      "claudeSignInButton": "Sign in with Claude",
      "claudeCallbackCodeLabel": "Authorization code",
      "claudeCallbackCodePlaceholder": "code#state",
      "claudeCallbackCodeHint": "Anthropic shows a value like `abc123#xyz`. Paste it here exactly — Avibe forwards it to Claude Code.",
      "claudeApiKeyLabel": "API key",
      "claudeApiKeyPlaceholder": "sk-ant-...",
      "claudeApiKeyConfigured": "A key of length {{length}} is currently stored.",
      "claudeApiKeyMissing": "No API key stored yet.",
      "claudeBaseUrlLabel": "Base URL (optional)",
      "claudeBaseUrlPlaceholder": "https://api.anthropic.com",
      "claudeBaseUrlHint": "Leave empty to use Anthropic's default endpoint. Compatible relays (e.g. Bedrock proxies, AWS endpoints) accept their own URL here.",
      "claudeBaseUrlReset": "Reset to default",
      "claudeSettingsConflictTitle": "Legacy Avibe key will be migrated",
      "claudeSettingsConflictBody": "Saving updates `{{var}}` in {{path}} and clears the old Avibe copy.",
      "claudeInfoHint": "Saving here writes Claude Code's `settings.json` env values. Claude relaunches per request, so no Avibe restart is needed.",
      "claudeSave": "Save Claude auth",
      "claudeSaving": "Saving…",
      "claudeSaveSuccess": "Claude auth saved",
      "claudeSaveFailed": "Could not save Claude auth",
      "oauthAuthUrlLabel": "Authorization URL",
      "oauthInProgress": "Login in progress…",
      "oauthStarting": "Starting OAuth flow…",
      "oauthVerifying": "Verifying credentials…",
      "oauthSuccess": "Signed in successfully.",
      "oauthFailed": "OAuth flow failed: {{detail}}",
      "oauthPollTimedOut": "Login did not complete within the allowed time. Please retry.",
      "oauthUrlCopied": "URL copied to clipboard.",
      "oauthDeviceCodeCopied": "Device code copied to clipboard.",
      "oauthReauthenticate": "Re-authenticate",
      "oauthRemove": "Sign out",
      "oauthRemoved": "Credentials removed.",
      "oauthRemoveFailed": "Could not remove credentials: {{detail}}",
      "oauthRemovePartial": "Credentials cleared from Avibe, but the backend CLI logout reported a problem: {{detail}}. The CLI's own files may still be present.",
      "oauthFlowLockedToast": "OAuth login is in progress — finish or cancel it before switching auth mode.",
      "testConnectionTitle": "Test connection",
      "testConnectionSubtitle": "Send a one-token \"Hi\" prompt to verify the session, the model, and any custom Base URL.",
      "testConnectionRun": "Run test",
      "testConnectionLastOk": "Last run: ok · {{ms}} ms",
      "testConnectionLastFail": "Last run failed: {{detail}}",
      "testConnectionModelLabel": "Test model",
      "testConnectionModelDefault": "Backend default",
      "testConnectionResponseLabel": "Model response",
      "testConnectionSuccessToast": "Backend reachable · {{ms}} ms",
      "testConnectionFailedToast": "Backend test failed: {{detail}}",
      "testFailureInvalidCredentials": "The stored credentials were rejected (401). Replace your API key or re-authenticate.",
      "testFailureForbidden": "The endpoint accepted the credentials but denied access (403). Check the relay's allowed-models list.",
      "testFailureModelNotFound": "The model the backend tried to use was not recognised by the endpoint. Check the model id or relay routing.",
      "testFailureRateLimited": "The endpoint returned rate-limited / quota-exceeded (429). Wait or rotate to a key with higher limits.",
      "testFailureEndpointUnreachable": "Could not reach the configured Base URL. Check DNS, proxy, and that the relay is up.",
      "testFailureServerError": "The endpoint responded with a 5xx error. The relay is reachable but not healthy.",
      "testFailureTrustCheck": "Codex refused to run from the current directory. Restart the regression container so the cwd is trusted.",
      "testFailureCliNotFound": "The backend CLI binary was not found. Check the Path on the runtime card.",
      "testFailureSpawnFailed": "Could not launch the backend CLI: {{detail}}",
      "testFailureTimedOut": "The CLI did not respond within the test timeout.",
      "testFailureCliFailed": "The CLI exited with an error. Expand the raw output below to see what it said.",
      "testConnectionRawOutputLabel": "Raw output",
      "activeAuthOauth": "Active: OAuth",
      "activeAuthApiKey": "Active: API Key",
      "activeAuthNone": "Not signed in",
      "replaceApiKey": "Replace",
      "claudeApiKeyRemove": "Remove key",
      "claudeApiKeyRemoveConfirm": "Remove the stored Anthropic API key? OAuth credentials are left untouched.",
      "claudeApiKeyRemoved": "Stored Anthropic API key removed.",
      "claudeApiKeyRemoveFailed": "Could not remove API key: {{detail}}",
      "codexApiKeyRemove": "Remove key",
      "codexApiKeyRemoveConfirm": "Remove the stored OpenAI API key from auth.json? Codex will fall back to OAuth tokens if present, or sit unconfigured if not.",
      "codexApiKeyRemoved": "Stored OpenAI API key removed.",
      "codexApiKeyRemoveFailed": "Could not remove API key: {{detail}}",
      "codexNoticeClearedRelayPointer": "Cleared the custom relay pointer ({{provider}} → {{url}}) because OAuth tokens won't validate against a custom base URL. Codex will now use OpenAI's default endpoint. To switch back, re-add an API key or edit ~/.codex/config.toml manually.",
      "codexNoticeGeneric": "Config notice: {{code}}",
      "opencodeProviderSignIn": "Sign in",
      "opencodeProviderOauthSignedIn": "OAuth credentials stored.",
      "opencodeProviderOauthPanelTitle": "Sign in to {{name}}",
      "opencodeProviderOauthPanelSubtitle": "Open the URL, complete login in your browser; the OpenCode daemon detects completion automatically.",
      "opencodeCallbackUrlLabel": "Callback URL",
      "opencodeCallbackUrlHint": "After authorizing, your browser will land on `http://127.0.0.1:<port>/callback?code=...` — copy that exact URL from the address bar and paste it here. Avibe replays it inside the container so OpenCode's listener receives the credential.",
      "opencodeProvidersTitle": "Providers",
      "opencodeProvidersSubtitle": "Lazy-loaded from the OpenCode server · auth handled via API key or OAuth sign-in",
      "opencodeProvidersCount": "{{configured}}/{{total}} configured",
      "opencodeServerRunning": "Server reachable",
      "opencodeServerStopped": "Server unavailable",
      "opencodeServerStarting": "Server starting…",
      "opencodeServerUnreachable": "Server not reachable",
      "opencodeServerRetryCount": "Retry {{attempt}}/{{max}}",
      "opencodeBackendDisabled": "Backend disabled",
      "opencodeDisabledBanner": "Enable OpenCode in the header to manage providers. The auth-mode toggle is the only interactive control while the backend is off.",
      "opencodeRefresh": "Refresh",
      "opencodeCustomProviderAdd": "Add compatible provider",
      "opencodeCustomProviderTitle": "Custom compatible provider",
      "opencodeCustomProviderSubtitle": "Create an OpenAI-compatible or Anthropic-compatible provider backed by OpenCode config.",
      "opencodeCustomProviderName": "Display name",
      "opencodeCustomProviderNamePlaceholder": "My Relay",
      "opencodeCustomProviderId": "Provider ID",
      "opencodeCustomProviderIdPlaceholder": "my-relay",
      "opencodeCustomProviderAdapter": "Compatibility",
      "opencodeCustomProviderAdapterOpenAI": "OpenAI compatible",
      "opencodeCustomProviderAdapterAnthropic": "Anthropic compatible",
      "opencodeCustomProviderRequired": "Name, Provider ID, and Base URL are required.",
      "opencodeCustomProviderIdInvalid": "Provider ID must start with a lowercase letter or number and use only lowercase letters, numbers, dot, hyphen, or underscore.",
      "opencodeCustomProviderBaseUrlInvalid": "Base URL must start with http:// or https://.",
      "opencodeCustomProviderSave": "Create provider",
      "opencodeCustomProviderSaved": "Custom provider saved.",
      "opencodeCustomProviderSaveFailed": "Could not save custom provider.",
      "opencodeCustomProviderBadge": "Custom",
      "opencodeCustomProviderRemove": "Delete provider",
      "opencodeCustomProviderRemoveConfirm": "Delete custom provider {{name}}? This removes its config, models, and stored credentials.",
      "opencodeCustomProviderRemoved": "Custom provider deleted.",
      "opencodeCustomProviderRemoveFailed": "Could not delete custom provider.",
      "opencodeSearchPlaceholder": "Search providers, models, IDs…",
      "opencodeFilterAll": "All",
      "opencodeFilterConfigured": "Configured",
      "opencodeFilterOauth": "OAuth available",
      "opencodeFilterLocal": "Local",
      "opencodeBadgeConfigured": "Configured",
      "opencodeBadgeConfiguredApiKey": "API Key",
      "opencodeBadgeConfiguredOauth": "OAuth",
      "opencodeBadgeOauth": "OAuth available",
      "opencodeBadgeLocal": "Local",
      "opencodeBadgeUnset": "Not set",
      "opencodeDefaultBadge": "Default",
      "opencodeDefaultLabel": "Default provider",
      "opencodeDefaultUnset": "Unset",
      "opencodeDefaultPopoverTitle": "Pick the default provider",
      "opencodeDefaultPopoverEmpty": "No providers match that search.",
      "opencodeDefaultNeedsKey": "{{name}} has no API key yet — set one to make it the default.",
      "opencodeDefaultSaved": "{{name}} is now the default provider.",
      "opencodeDefaultSaveFailed": "Could not change the default provider.",
      "opencodeProvidersLoading": "Loading providers from OpenCode…",
      "opencodeProvidersEmpty": "OpenCode returned no providers. Run `opencode auth list` from a terminal to diagnose.",
      "opencodeProvidersFilterEmpty": "No providers match the current search or filter.",
      "opencodeProvidersError": "Could not load the OpenCode provider catalog.",
      "opencodeProvidersInfo": "Provider data is fetched live from the OpenCode server.",
      "opencodeProviderModelsCount": "{{count}} models",
      "opencodeProviderModelsEmpty": "No models yet. Add a model ID above to use this provider.",
      "opencodeProviderModels": "Models",
      "opencodeProviderDefaultModel": "Default",
      "opencodeProviderAddModel": "Add model",
      "opencodeProviderModelPlaceholder": "model-id, without provider/",
      "opencodeProviderModelAdd": "Add model",
      "opencodeProviderModelReasoning": "Reasoning",
      "opencodeProviderModelHint": "User-added models are written to OpenCode config and appear in this provider's test dropdown.",
      "opencodeProviderModelRequired": "Enter a model ID before adding it.",
      "opencodeProviderModelNoProviderPrefix": "Enter only the model ID here, without the provider/ prefix.",
      "opencodeProviderModelDuplicate": "That model ID already exists for this provider.",
      "opencodeProviderModelSaveFailed": "Could not save the model.",
      "opencodeProviderModelSaved": "Model saved.",
      "opencodeProviderModelRemoveFailed": "Could not remove the model.",
      "opencodeProviderModelRemoved": "Model removed.",
      "opencodeProviderUserModel": "Manual",
      "opencodeProviderUserModelsCount": "{{count}} manual",
      "opencodeProviderApiKey": "API key",
      "opencodeProviderApiKeyPlaceholder": "Paste the provider's API key",
      "opencodeProviderApiKeyPlaceholderStored": "Enter a new key to replace the stored one",
      "opencodeProviderApiKeyStored": "A key is currently stored on disk.",
      "opencodeProviderApiKeyMissing": "No API key stored for this provider yet.",
      "opencodeProviderApiKeyRequired": "Enter the provider's API key before saving.",
      "opencodeProviderBaseUrl": "Base URL (optional)",
      "opencodeProviderBaseUrlPlaceholder": "https://provider.example.com/v1",
      "opencodeProviderBaseUrlHint": "Provider-level overrides go in `~/.config/opencode/opencode.json`. Leave empty to use the provider's default.",
      "opencodeProviderBaseUrlRequired": "Base URL is required for custom providers.",
      "opencodeProviderOauthAvailable": "OAuth login available",
      "opencodeProviderOauthHint": "You can also run `opencode auth login {{id}}` in a terminal to authenticate without storing a key here.",
      "opencodeProviderLocalHint": "Local providers do not need credentials — start the runtime and load a model.",
      "opencodeProviderSave": "Save key",
      "opencodeProviderSaved": "Provider credentials saved.",
      "opencodeProviderCatalogRefreshPending": "Provider saved. Refreshing the model list…",
      "opencodeProviderSaveFailed": "Could not save provider credentials.",
      "opencodeProviderRemove": "Remove key",
      "opencodeProviderRemoveOauth": "Sign out",
      "opencodeProviderRemoveConfirm": "Remove the saved key for {{name}}?",
      "opencodeProviderRemoveOauthConfirm": "Sign out of {{name}}? This removes the stored OAuth credentials.",
      "opencodeProviderRemoved": "Provider credentials removed.",
      "opencodeProviderRemoveFailed": "Could not remove provider credentials.",
      "opencodeProviderCollapse": "Collapse",
      "opencodeTestTitle": "Test {{name}}",
      "opencodeTestSubtitle": "Send a one-token \"Hi\" through OpenCode using this provider only.",
      "opencodeTestModelDefault": "Provider default",
      "testFailureOpencodeServerUnavailable": "OpenCode's local server is not reachable. Start it from the Runtime page and retry.",
      "testFailureNoModels": "This provider has not reported any models yet. Save a key first, or open the provider catalog.",
      "testFailureSessionCreate": "OpenCode rejected the test session — check the server logs for a deeper error.",
      "testFailureMissingProvider": "Provider id is missing — reload the page and try again."
    },
    "messagingTitle": "Messaging",
    "messagingSubtitle": "Tune global reply behavior, acknowledgements, and message visibility defaults.",
    "messagingCardDescription": "Fine-tune how Avibe acknowledges work, retries failures, and formats user-facing replies.",
    "messagingAutosaved": "Autosaved",
    "messagingStatusIdle": "No recent changes",
    "messagingStatusJustNow": "Saved just now",
    "messagingStatusAgo": "Saved {{seconds}}s ago",
    "messagingInputEnrichmentTitle": "Input enrichment",
    "messagingInputEnrichmentDescription": "Transform inbound user content before it reaches an agent.",
    "messagingAgentContextTitle": "Agent context",
    "messagingAgentContextDescription": "Metadata prepended to each user turn sent to an agent.",
    "messagingWorkFeedbackTitle": "Work feedback",
    "messagingWorkFeedbackDescription": "How Avibe acknowledges, retries, and reports running work.",
    "messagingReplyExperienceTitle": "Reply experience",
    "messagingReplyExperienceDescription": "Controls for messages Avibe sends back into chat.",
    "messagingDisplayTitle": "Chat display",
    "messagingDisplayDescription": "Tune how conversations are rendered in the Web UI.",
    "messagingGroupsTitle": "Groups and routing",
    "messagingGroupsDescription": "Jump to group allow-list and per-group backend routing.",
    "messagingGroupsHint": "Manage which groups are allowed and how each one routes to an agent backend.",
    "messagingSupportTitle": "Platform support",
    "messagingSupportLine1": "Typing indicators and reaction-based acknowledgements depend on the capabilities of the platforms you enabled.",
    "messagingSupportLine2": "Slack-specific link preview suppression is shown only when Slack is part of the active platform set.",
    "messagingSupportLine3": "For per-group overrides, open the Groups page and change routing there instead of relying on the global defaults alone.",
    "messagingBehaviorTitle": "Current behavior snapshot",
    "diagnosticsTitle": "Diagnostics",
    "diagnosticsSubtitle": "Run health checks, inspect warnings, and jump into live logs when something is off.",
    "diagnosticsDoctorTitle": "Health checks",
    "logsTitle": "Live logs",
    "logsSubtitle": "Inspect the runtime log stream with filters, search, and source selection.",
    "inProgressTitle": "This settings page is next in the redesign queue",
    "inProgressBody": "The new route and shell are live, but the feature-specific UI for this section is still being migrated from the old dashboard and wizard flows.",
    "inProgressHint": "Until this section is rebuilt, the setup wizard still exposes the underlying configuration paths.",
    "openSetup": "Open setup wizard"
  },
  "remoteAccess": {
    "badge": "Avibe Cloud provider",
    "title": "Remote Access",
    "subtitle": "Open this local Web UI from another device through a private avibe.bot URL. Your data and agents still run on this machine.",
    "subtitleWithLink": "Open this local Web UI from another device through a private <cloud>avibe.bot</cloud> URL. Your data and agents still run on this machine.",
    "connectTitle": "Connect to Avibe Cloud",
    "connectDesc": "First create a remote-access bot at avibe.bot and copy its one-time pairing key. Then paste it here to pair this device.",
    "configuredTitle": "Avibe Cloud is configured",
    "configuredDesc": "This machine has saved the remote-access credentials. The pairing key was one-time use; after restart, Avibe uses the saved connection credentials.",
    "configuredBadge": "Connected to Avibe Cloud",
    "configuredHelp": "Use re-pair only when switching account, changing domain, or regenerating remote access.",
    "legacyHostnameTitle": "This remote address needs to be replaced",
    "legacyHostnameDesc": "Older instances used *.remote.avibe.bot. That is a nested hostname and may fail TLS on Cloudflare Universal SSL. Create a new remote-access bot at avibe.bot, then re-pair here to receive a *.avibe.bot address.",
    "vibeCloudService": "Avibe Cloud service",
    "backendUrl": "Avibe Cloud URL",
    "pairingKey": "Pairing key",
    "pairingKeyHelp": "The pairing key is shown once and usually starts with vrp_. After redemption, Avibe stores connection credentials, not this one-time key.",
    "pair": "Pair and start",
    "pairing": "Pairing...",
    "repair": "Re-pair",
    "pairSuccess": "Remote access paired",
    "startSuccess": "Remote access started",
    "stopSuccess": "Remote access stopped",
    "statusTitle": "Runtime status",
    "statusDesc": "Remote URL and runtime status.",
    "paired": "Pairing",
    "connector": "Remote access",
    "flowTitle": "Setup steps",
    "flowStep1": "Open avibe.bot, sign up or sign in, create a remote-access bot, and claim your personal domain.",
    "flowStep2": "Copy the one-time pairing key shown in the avibe.bot console.",
    "flowStep3": "Paste the key here. Avibe saves the connection credentials and starts remote access.",
    "actionNeeded": "Action needed",
    "ready": "Ready",
    "stateNeedsAttention": "Needs attention"
  },
  "accessBlocked": {
    "title": "Can't open the control panel here",
    "body": "Avibe is running, but it refused to open the control panel at this address.",
    "hint": "Open Avibe from your https://<your-slug>.avibe.bot link, or use http://127.0.0.1:5123 on the machine running Avibe. A raw LAN or Tailscale IP is blocked while remote access is on.",
    "codeLabel": "Reason",
    "retry": "Retry"
  },
  "errors": {
    "project_no_folder": "This project has no local folder configured.",
    "project_not_found": "Project not found.",
    "remote_access_host_mismatch": "This address can't open the Avibe control panel. Open it from your https://<your-slug>.avibe.bot link, or http://127.0.0.1:5123 on the machine running Avibe.",
    "remote_access_config_unavailable": "Avibe couldn't read its configuration. Check that the service is healthy and try again.",
    "remote_access_public_url_invalid": "Remote access is misconfigured (the public URL is invalid). Re-pair this device or fix the remote-access settings.",
    "remote_access_session_secret_missing": "Remote access is misconfigured (missing session secret). Re-pair this device to restore access.",
    "remote_access_unknown": "The operation did not finish. Refresh the status and try again; if it still fails, check the remote access runtime logs.",
    "invalid_pairing_key": "This pairing key is invalid or expired. Create a new key at avibe.bot, then paste it here.",
    "missing_pairing_key": "Paste the pairing key first.",
    "pairing_request_failed": "Could not connect to avibe.bot. Check the network connection and make sure the Avibe Cloud URL is correct.",
    "backend_http_error": "avibe.bot rejected this request. Try again later, or create a new pairing key.",
    "invalid_pairing_response": "avibe.bot returned incomplete pairing data. Refresh the page, create a new pairing key, and try again.",
    "remote_access_disabled": "Remote access is not enabled yet. Pair this device first.",
    "missing_tunnel_token": "Pairing data is incomplete because the Tunnel credential is missing. Pair this device again.",
    "cloudflared_install_failed": "Connector installation failed. Check network access and local write permissions, then try again.",
    "cloudflared_spawn_failed": "Connector startup failed. Check that cloudflared is executable, or inspect the runtime logs.",
    "cloudflared_exited": "The connector exited immediately after startup. This usually means the Tunnel credential is invalid or the Cloudflare config is not ready. Pair again and retry.",
    "cloudflared_stop_failed": "The connector could not be stopped. Try again later, or manually stop the cloudflared process.",
    "cloudflared_process_unknown": "Avibe found a connector-like process but could not verify ownership. To avoid killing the wrong process, it did not change it. Check the cloudflared process manually and retry."
  },
  "appShell": {
    "title": "Avibe OS",
    "subtitle": "Agent OS",
    "workspaceLabel": "Workspace",
    "openControlPanel": "Control Panel",
    "backToWorkbench": "Back to Workbench",
    "newSession": "New",
    "navigationLabel": "Console",
    "statusLabel": "Service status",
    "versionLabel": "Version",
    "accountMenuLabel": "Account ({{email}})",
    "signedInAs": "Signed in as",
    "signOut": "Sign out",
    "signingOut": "Signing out…"
  },
  "workbench": {
    "eyebrow": "Workbench",
    "placeholderTitle": "Your AI workbench is coming together",
    "placeholderBody": "Agents, Skills, Harness, and Vaults will live here. For now, jump into the control panel to configure platforms and backends.",
    "canvas": {
      "heroTitle": "What should we build today?",
      "heroBody": "Describe what you want and an agent will run it. Or start with one of the suggestions below.",
      "suggestions": {
        "newProject": "Open project",
        "newProjectHint": "Pick a folder; sessions default to it",
        "openAgents": "Manage agents",
        "openAgentsHint": "Add or tweak available agents",
        "openHarness": "Schedule background work",
        "openHarnessHint": "Have an agent write the cron / watch"
      },
      "inputPlaceholder": "Tell the agent what you want…",
      "noProjectForChat": "No projects yet — add one before starting a chat"
    },
    "openControlPanel": "Open Control Panel",
    "capabilitiesLabel": "Capabilities",
    "projectsLabel": "Projects",
    "addProject": "Open project",
    "addSession": "New session in this project",
    "projectActions": "Project actions",
    "sessionActions": "Session actions",
    "projectRename": "Rename",
    "projectSettings": "Project settings",
    "projectEditAgents": "Edit AGENTS.md",
    "projectArchive": "Archive",
    "projectArchiveConfirm": "Archive project \"{{name}}\"? Session history is preserved; it just stops showing in the sidebar.",
    "projectRenamePlaceholder": "New name",
    "sessionRename": "Rename",
    "sessionRenamePlaceholder": "Session name",
    "sessionArchive": "Archive session",
    "archiveSession": {
      "title": "Archive this session permanently?",
      "body": "“{{name}}” will be permanently archived and can't be restored.",
      "checking": "Checking linked resources…",
      "previewError": "Couldn't verify linked resources — they'll still be permanently deleted.",
      "reclaimIntro": "These linked resources will be permanently deleted:",
      "reclaimTasks": "{{n}} scheduled task(s)",
      "reclaimWatches": "{{n}} watch(es)",
      "reclaimRuns": "{{n}} in-progress run(s)",
      "reclaimQueued": "{{n}} queued message(s)",
      "noReclaim": "No scheduled tasks or watches are linked to this session.",
      "confirm": "Archive permanently"
    },
    "projectsEmpty": "No projects yet — add one to start a session.",
    "projectsLoading": "Loading projects…",
    "projectsLoadError": "Couldn't load projects.",
    "sessionsLoading": "Loading sessions…",
    "sessionsEmpty": "No sessions in this project.",
    "sessionsLoadMore": "Load more",
    "untitledSession": "Untitled session",
    "sessionStatus": {
      "idle": "Idle",
      "running": "Running",
      "failed": "Last turn failed"
    },
    "newProjectDialog": {
      "title": "Open project",
      "description": "Pick a working directory. Opening a folder you've used before reopens that project — restoring it if it was archived.",
      "pickFolder": "Choose folder",
      "displayName": "Display name",
      "displayNamePlaceholder": "Auto from folder name",
      "folderLabel": "Folder",
      "create": "Open project",
      "creating": "Opening…",
      "cancel": "Cancel"
    },
    "nav": {
      "inbox": "Inbox",
      "agents": "Agents",
      "skills": "Skills",
      "harness": "Harness",
      "vaults": "Vaults"
    },
    "inbox": {
      "eyebrow": "Inbox",
      "title": "Inbox",
      "headerCount": "{{unread}} unread · {{total}} total",
      "markAllRead": "Mark all read",
      "markRead": "Mark read",
      "viewAll": "Open full inbox",
      "openSession": "Open session",
      "refresh": "Refresh",
      "filterUnread": "Unread",
      "filterAll": "All",
      "empty": "Nothing in your inbox yet — agent replies will surface here.",
      "emptyTitle": "Inbox is empty",
      "emptyBody": "When an agent posts back from a session, it shows up here.",
      "allClearTitle": "All caught up",
      "allClearBody": "No unread agent messages right now. Switch to \"All\" to browse history.",
      "backToCanvas": "Back to canvas",
      "agent": "Agent",
      "you": "You",
      "replied": "Replied",
      "loadMore": "Load more",
      "moreUnreadBeyond": "More unread sessions may be further down — load more to see them.",
      "notifications": {
        "checking": "Checking notifications",
        "unsupported": "Notifications unavailable",
        "installFirst": "Add to Home Screen first",
        "enable": "Enable notifications",
        "enabled": "Notifications on",
        "enabledPwa": "PWA notifications on",
        "disable": "Disable",
        "test": "Test",
        "testTitle": "Avibe",
        "testBody": "Notifications are ready.",
        "testSent": "Test notification sent",
        "testFailed": "Test notification failed"
      }
    },
    "modules": {
      "comingSoonEyebrow": "Coming soon",
      "comingSoon": "This capability is still on the way — the full surface lands in a later release.",
      "inbox": {
        "eyebrow": "Inbox",
        "title": "Inbox",
        "description": "Cross-project notifications from every Avibe session. Hover popover + full list view will land in a later commit."
      },
      "agents": {
        "eyebrow": "Agents",
        "title": "Agents",
        "description": "Global registry of every Avibe Agent — Claude / OpenCode / Codex variants you can pick when starting a session."
      },
      "skills": {
        "eyebrow": "Skills",
        "title": "Skills",
        "description": "Manage Agent Skills (global + project-scoped) on top of the askill CLI."
      },
      "harness": {
        "eyebrow": "Harness",
        "title": "Harness",
        "description": "Background tasks, watches, webhooks, and the run history of all three. Created by chatting with an Agent."
      },
      "vaults": {
        "eyebrow": "Vaults",
        "title": "Vaults",
        "description": "Secrets and API keys that the Agent can pull into ENV / .env without you copy-pasting."
      }
    }
  },
  "wizard": {
    "title": "Avibe Setup"
  },
  "welcome": {
    "title": "Welcome to Avibe",
    "subtitle": "This machine is now home to your AI agent. Talk to it from the built-in Workbench — or connect Slack, Discord, Telegram, Lark, and WeChat.",
    "getStarted": "Get started",
    "card1Title": "Local-first",
    "card2Title": "Multi-platform",
    "card3Title": "Multi-agent",
    "feature1": "Your data + agents stay on your machine.",
    "feature2": "Slack, Discord, Telegram, Lark, WeChat — one place.",
    "feature3": "Claude, OpenCode, Codex — route per channel."
  },
  "modeSelection": {
    "title": "Choose Mode",
    "saasMode": "SaaS Mode",
    "saasDescription": "OAuth install + cloud relay + local execution (coming soon).",
    "selfHostMode": "Self-host Mode",
    "selfHostDescription": "Use your own platform credentials and keep execution local."
  },
  "platform": {
    "eyebrow": "03 — Platforms",
    "title": "Where you'll talk to your agent",
    "subtitle": "Your Avibe Workbench is always on — a built-in web app you can even add to your phone's home screen. Connect chat platforms like Slack or Telegram too, or skip and set them up later.",
    "workbenchRequired": "REQUIRED",
    "workbenchDesc": "Your built-in web chat for talking to agents — always on, nothing to set up.",
    "workbenchPwa": "Add to your phone's home screen — use it like a native app.",
    "workbenchAlwaysOn": "Always enabled",
    "chatPlatformsTitle": "Chat platforms",
    "optionalLabel": "OPTIONAL",
    "primary": "Primary",
    "primaryTitle": "Primary Platform",
    "primaryDesc": "Used for compatibility ordering and default UI focus.",
    "credentialsTitle": "Platform credentials",
    "credentialsSubtitle": "Connect each IM platform with the credentials your bot uses to authenticate.",
    "enabledPlatforms": "Enabled platforms",
    "selectedSummary": "{{count}} selected",
    "apply": "Apply",
    "applyHint": "Apply updates to the credential tabs below, disabled platforms keep saved tokens.",
    "configureBeforeEnable": "Configure and save this platform before enabling it.",
    "applyingConfig": "Applying configuration...",
    "restartingService": "Restarting service to apply changes...",
    "restartedSuccess": "Configuration applied and service restarted",
    "restartFailed": "Configuration saved, but service restart failed",
    "credentialSetupTitle": "{{platform}} workspace setup",
    "credentialSetupSubtitle": "Configure the selected platform directly here, then validate credentials before enabling groups.",
    "stepCreateApp": "Create platform app",
    "stepAddBotToken": "Add bot token",
    "stepConfigureOptions": "Configure platform options",
    "stepValidate": "Validate & finish",
    "expanded": "Expanded",
    "collapsed": "Collapsed",
    "expandedStepHint": "Use this shared setup module for {{platform}} credentials.",
    "credentialGuide": "Open the platform console, copy the required credentials, paste them below, then validate the connection.",
    "openConsole": "Open {{platform}} console",
    "validateToken": "Validate token",
    "validationSuccess": "Credential validation succeeded",
    "validationFailed": "Credential validation failed",
    "wechatCredentialHint": "WeChat uses QR binding. Rebinding and login status remain in the WeChat setup flow.",
    "slack": {
      "title": "Slack",
      "desc": "Connect a Slack workspace and enable groups."
    },
    "discord": {
      "title": "Discord",
      "desc": "Connect a Discord bot and choose a guild."
    },
    "telegram": {
      "title": "Telegram",
      "desc": "Connect a Telegram bot for DMs, groups, and forum topics."
    },
    "lark": {
      "title": "Lark",
      "desc": "Connect to Feishu/Lark workspace for team collaboration"
    },
    "wechat": {
      "title": "WeChat",
      "desc": "Connect to WeChat personal messaging via iLink bot"
    },
    "avibe": {
      "title": "Avibe Workbench",
      "desc": "Chat with your agents directly in this local web workbench."
    }
  },
  "discordConfig": {
    "eyebrow": "Discord",
    "title": "Discord Configuration",
    "subtitle": "Create a Discord app, invite the bot, then add your token.",
    "botToken": "Bot Token",
    "botTokenPlaceholder": "Paste your Discord bot token",
    "botTokenHint": "Use the token from the Discord Developer Portal.",
    "validateToken": "Validate Token",
    "tokenValidated": "Token validated",
    "authFailed": "Validation failed",
    "guild": "Guilds where the bot can work",
    "guildPlaceholder": "No guilds loaded",
    "guildHint": "This controls which Discord guilds the bot can work in. Configure group enablement and routing in the next step.",
    "selectedGuilds": "{{count}} selected",
    "selectAllGuilds": "Select all",
    "clearGuilds": "Clear",
    "step1Title": "Create Discord App",
    "step1Description": "Create a new application in the Developer Portal.",
    "step1Item1": "Open the Discord Developer Portal",
    "step1Item2": "Click \"New Application\" and name it",
    "step1Item3": "Open the Bot tab (your bot is created automatically)",
    "openDeveloperPortal": "Open Developer Portal",
    "step2Title": "Enable Message Content Intent",
    "step2Description": "Enable Message Content Intent in the Bot tab. Permissions are included in the invite link.",
    "step2Item1": "In the Bot tab, enable \"Message Content Intent\" and save",
    "step2Item2": "No need to set Bot Permissions here",
    "step2Tip": "Message Content Intent is required to read message text.",
    "step3Title": "Generate Invite URL",
    "step3Description": "Paste your Client ID and we will generate a ready-to-use OAuth2 invite link.",
    "step3Item1": "In your app, open General Information and copy Client ID",
    "step3Item2": "Paste it below to generate the invite URL",
    "step3Item3": "Permissions are prefilled in the invite URL",
    "step3Item4": "Open the invite URL, choose a server, and authorize",
    "clientId": "Client ID",
    "clientIdPlaceholder": "Paste Client ID",
    "clientIdHint": "Find this in General Information of your Discord application.",
    "inviteUrlLabel": "OAuth2 Invite URL",
    "inviteUrlPlaceholder": "Invite URL will appear here after Client ID",
    "inviteUrlCopy": "Copy URL",
    "inviteUrlCopied": "Copied",
    "openInviteUrl": "Open OAuth2 Invite URL",
    "openUrlGenerator": "Open OAuth2 URL Generator",
    "step4Title": "Add Token & Validate",
    "step4Description": "Copy the bot token and validate access.",
    "step4Item1": "In the Bot tab, click \"Reset Token\" or \"View Token\"",
    "step4Item2": "Copy the token and paste it here",
    "step4Item3": "Validate the token and choose a guild",
    "dmTroubleshootTitle": "DM Troubleshooting",
    "dmTroubleshoot1": "Make sure your account and the bot are in at least one common server.",
    "dmTroubleshoot2": "In server Privacy Settings, enable \"Allow direct messages from server members\".",
    "dmTroubleshoot3": "Ensure you didn't block the bot account."
  },
  "telegramConfig": {
    "eyebrow": "Telegram",
    "title": "Telegram Configuration",
    "subtitle": "Create a Telegram bot, validate the token, then finish the group setup in a few guided steps.",
    "step1Title": "Create Bot with BotFather",
    "step1Description": "Use @BotFather to create a new bot and prepare the API token.",
    "step1Item1": "Open @BotFather in Telegram",
    "step1Item2": "Send /newbot and follow the prompts",
    "step1Item3": "Choose a display name for the bot",
    "step1Item4": "Choose a username ending in \"bot\" and keep the generated token page open",
    "step1Tip": "If you already created the bot, you can skip straight to copying the token in Step 2.",
    "openBotFather": "Open BotFather",
    "copyNewBotCommand": "Copy /newbot",
    "copiedCommand": "Copied",
    "step2Title": "Paste Token & Validate",
    "step2Description": "Copy the bot token from BotFather and verify that Avibe can talk to the bot.",
    "step2Item1": "In BotFather, open your bot and choose the API token option",
    "step2Item2": "Copy the token and paste it below",
    "step2Item3": "Validate the token before continuing",
    "step3Title": "Finish BotFather Initialization",
    "step3Description": "Set the BotFather switches that directly control whether the bot can join groups and receive the messages you expect.",
    "step3Item1": "Run the commands below in BotFather and select your bot each time",
    "step3Item2": "If you want normal group messages without @mentions, set privacy mode to Disable",
    "step3Item3": "If the bot should be used in groups or forums, make sure group joining is enabled",
    "step3Item4": "Publish the common slash commands so new users can discover them from the Telegram command picker",
    "step3Command1Title": "Disable group privacy mode",
    "step3Command1Description": "Send /setprivacy, choose your bot, then select Disable. Otherwise Telegram forwards only commands, @mentions, and replies to the bot.",
    "step3Command2Title": "Allow the bot to join groups",
    "step3Command2Description": "Send /setjoingroups, choose your bot, and make sure it is set to Enable so the bot can be added to groups and forums normally.",
    "step3Command3Title": "Publish the bot command menu",
    "step3Command3Description": "Send /setcommands and add common commands like /start, /settings, /new, and /resume so users immediately see what the bot can do.",
    "step3TipTitle": "Most commonly missed",
    "step3Tip": "If you expect the bot to respond to normal group messages without explicit @mentions, /setprivacy must be set to Disable. This is the most common Telegram setup miss.",
    "step3ExtraTip": "If you only need the bot in DMs for now, /setjoingroups can wait. But before using groups or forum topics, finish it first.",
    "step4Title": "Finish Setup, Bind, Then Discover Chats",
    "step4Description": "Telegram chat discovery happens only after Avibe is running and has received inbound messages. Finish setup first, then come back from the dashboard to enable discovered group or forum chats.",
    "step4Item1": "Finish the setup flow and start the service",
    "step4Item2": "On the summary screen, copy the first bind command and send `bind <code>` or `/bind <code>` to the bot in DM",
    "step4Item3": "After binding, send /start in DM; for groups or forums, add the bot there and grant message permission (plus admin/topic-management rights if you want forum auto-topic mode)",
    "step4Item4": "Send one message in each target group or forum chat, then refresh the Telegram chat list later from the dashboard group settings page",
    "step4Tip": "Direct messages stay hidden from the selectable Telegram chat list. If the bot still reacts only to commands or @mentions in groups, go back to Step 3 and verify that /setprivacy is really set to Disable.",
    "step5Title": "Choose Conversation Defaults",
    "step5Description": "Set the default group reply behavior and forum topic behavior for this bot.",
    "botToken": "Bot Token",
    "botTokenPlaceholder": "Paste your Telegram bot token",
    "botTokenHint": "Create a bot with @BotFather, then paste the token here.",
    "proxyUrl": "Proxy URL (optional)",
    "proxyUrlHint": "SOCKS5, SOCKS4, HTTP or HTTPS proxy. Leave empty if Telegram is accessible directly.",
    "validateToken": "Validate Token",
    "tokenValidated": "Token validated",
    "authFailed": "Validation failed",
    "requireMention": "Require explicit bot targeting in groups",
    "requireMentionHint": "When enabled, the bot responds in groups only when explicitly addressed by command, mention, or reply.",
    "forumAutoTopic": "Forum auto-topic mode",
    "forumAutoTopicHint": "For forum-enabled supergroups, new top-level messages can automatically create a new topic that becomes the session container. This requires the bot to have admin or topic-management rights in that chat."
  },
  "larkConfig": {
    "eyebrow": "Lark / Feishu",
    "title": "Configure Lark",
    "subtitle": "Set up your Lark/Feishu bot in a few steps",
    "domainLabel": "Platform Region",
    "domainFeishu": "Feishu (China)",
    "domainLark": "Lark (International)",
    "domainHint": "Select Feishu if your organization uses feishu.cn, or Lark if it uses larksuite.com",
    "step1Title": "Create App",
    "step1Description": "Create a self-built application on the Open Platform and add the Bot capability.",
    "step1Item1": "Go to the Open Platform and click \"Create App\"",
    "step1Item2": "Select \"Enterprise Self-Built App\" and fill in the app details",
    "step1Item3": "In the app capabilities, add \"Bot\"",
    "openPlatform": "Open Platform",
    "step2Title": "Enter Credentials & Validate",
    "step2Description": "Enter your App ID and App Secret from the \"Credentials & Basic Info\" page.",
    "step2ConnectingWs": "Establishing connection...",
    "step2WsConnected": "Connection established. You can now configure events in the next step.",
    "appId": "App ID",
    "appIdPlaceholder": "cli_xxxxxxxxxx",
    "appIdHint": "Found in Credentials & Basic Info page",
    "appSecret": "App Secret",
    "appSecretPlaceholder": "Enter your App Secret",
    "appSecretHint": "Click to reveal and copy from the Open Platform",
    "proxyUrlLarkLimitation": "Heads-up: lark-oapi has no proxy hook today, so the SDK message path bypasses this proxy. Auth and direct REST calls honor it.",
    "validateCredentials": "Validate Credentials",
    "credentialsValidated": "Credentials validated",
    "authFailed": "Validation failed",
    "chatListLabel": "Bot's Chat Groups",
    "chatListHint": "These are the groups the bot has joined. You can enable specific groups in the next step.",
    "step3Title": "Configure Permissions",
    "step3Description": "In Permission Management, click \"Batch Import/Export Permissions\" to enable the following permissions.",
    "step3Item1": "im:message — Send and receive messages",
    "step3Item2": "im:message:send_as_bot — Send messages as bot",
    "step3Item3": "im:message.group_at_msg — Receive group @messages",
    "step3Item4": "im:message.group_msg — Receive all group messages (required for non-@mention mode)",
    "step3Item5": "im:message.p2p_msg — Receive DM messages",
    "step3Item6": "im:resource — Upload/download files and images",
    "step3Item7": "im:chat — Access chat/group information",
    "step3Item8": "im:message.reactions — Read/write emoji reactions",
    "step3Item9": "contact:contact.base:readonly — Read user basic info",
    "step3Item10": "im:message:update — Edit/update sent messages and cards",
    "step3Item11": "im:message:recall — Recall (delete) bot messages",
    "step3Item12": "cardkit:card:write — Create and manage card templates",
    "step3Item13": "cardkit:card:read — Read card templates",
    "step3Item14": "contact:user.base:readonly — Read user basic info (legacy scope)",
    "step3BatchImport": "Quick setup: Copy JSON and use \"Batch Import/Export Permissions\"",
    "step3CopyJson": "Copy JSON",
    "step3Copied": "Copied!",
    "step3BatchImportHint": "In Permission Management, click \"Batch Import/Export Permissions\", paste this JSON, and confirm.",
    "step3ManualList": "Or manually enable permissions one by one",
    "step3OpenLink": "Open Permission Management",
    "step4Title": "Configure Events, Callbacks & Long Connection",
    "step4Description": "Subscribe to message events and card callbacks, then enable long connection so the bot can receive messages and respond to button interactions in real time.",
    "step4EventTitle": "A. Event Configuration",
    "step4Item1": "Switch to the \"Event Configuration\" tab",
    "step4Item2": "Set subscription method to \"Use Long Connection\"",
    "step4Item3": "Click \"Add Event\" and subscribe to \"Receive Messages im.message.receive_v1\"",
    "step4CallbackTitle": "B. Callback Configuration",
    "step4CallbackDesc": "Callbacks handle card button clicks. Without this, menu buttons will not work.",
    "step4CallbackItem1": "Switch to the \"Callback Configuration\" tab",
    "step4CallbackItem2": "Click \"Add Callback\" and add \"Card Interaction card.action.trigger\"",
    "step4CallbackItem3": "Set subscription method to \"Use Long Connection\" as well",
    "step4Tip": "Both events and callbacks must be configured, otherwise the bot cannot receive messages or respond to button actions. Remember to publish a new version after configuration.",
    "step4OpenLink": "Open Events & Callbacks",
    "step4LongConnFaqTitle": "Can't find \"Use Long Connection\"?",
    "step4LongConnFaqDesc": "If you only see \"Send events to developer server\", your app may not have the Bot capability enabled. Go back to Step 1, enter your app → Add Capabilities → enable \"Bot\". After saving, return to Events & Callbacks and the \"Use Long Connection\" option will appear.",
    "step4LarkWsWarning": "Lark (International) may not have the WebSocket option. If it is unavailable, please use the domestic Feishu version instead.",
    "step5Title": "Publish App",
    "step5Description": "Create and publish a version to make the app available in your organization.",
    "step5Item1": "Create a new version and submit for release",
    "step5Tip": "After publishing, all configurations (permissions, events, bot capability) will take effect.",
    "step5OpenLink": "Open Version Management"
  },
  "wechatConfig": {
    "eyebrow": "WeChat",
    "title": "WeChat Setup",
    "subtitle": "Scan the QR code with your WeChat to connect.",
    "stepStart": "Start",
    "stepScan": "Scan",
    "stepDone": "Done",
    "startDescription": "Click the button below to generate a WeChat login QR code. You will scan it with your phone to connect.",
    "startLogin": "Generate QR Code",
    "starting": "Generating...",
    "startFailed": "Failed to start login flow",
    "waitingForScan": "Waiting for you to scan the QR code...",
    "confirmOnPhone": "Scanned! Please confirm on your phone.",
    "scanHint": "Open WeChat on your phone and scan this QR code to log in.",
    "connected": "WeChat connected successfully!",
    "connectedTitle": "Connected",
    "connectionEstablished": "WeChat connection established",
    "nextStepTitle": "Next Step",
    "nextStepDesc": "You can now send `/start` in WeChat to open the menu.",
    "qrExpired": "QR code expired. Please try again.",
    "pollError": "An error occurred while checking status.",
    "errorTitle": "Connection Failed",
    "retry": "Try Again",
    "refreshQr": "Refresh QR Code",
    "alreadyBound": "WeChat Connected",
    "alreadyBoundDesc": "Your WeChat account is already linked. You can proceed or rebind with a different account.",
    "rebind": "Rebind Account"
  },
  "slackConfig": {
    "eyebrow": "04 — Slack",
    "title": "Slack Configuration",
    "saasDescription": "Authorize the official Slack app and wait for workspace binding.",
    "selfHostDescription": "Create a Slack app and configure tokens for Socket Mode.",
    "oauthPrompt": "Open OAuth in your browser to authorize Avibe with your Slack workspace.",
    "openSlackOAuth": "Open Slack OAuth",
    "afterAuth": "After authorization, return here to continue.",
    "botToken": "Bot User OAuth Token",
    "botTokenPlaceholder": "xoxb-... (paste here)",
    "botTokenHint": "Starts with",
    "appToken": "App-Level Token",
    "appTokenPlaceholder": "xapp-... (paste here)",
    "appTokenHint": "Starts with",
    "validateTokens": "Validate Tokens",
    "tokenValidated": "Tokens validated",
    "authFailed": "Validation failed",
    "tip": "Tip",
    "important": "Important",
    "viewManifest": "View manifest JSON",
    "step1Title": "Create Slack App",
    "step1Description": "Click the button below to create a new Slack app with pre-configured permissions.",
    "step1Tip": "The manifest will be auto-filled. Just select your workspace and click Create.",
    "createSlackApp": "Create Slack App",
    "copyManifest": "Copy Manifest",
    "copied": "Copied!",
    "step2Title": "Get Bot Token",
    "step2Description": "Install the app to your workspace and copy the Bot Token.",
    "step2Item1": "In your new app, go to 'OAuth & Permissions'",
    "step2Item2": "Click 'Install to [Your Workspace]'",
    "step2Item3": "Authorize the app",
    "step2Item4": "Copy the 'Bot User OAuth Token'",
    "step3Title": "Get App Token",
    "step3Description": "Generate an App-Level Token for Socket Mode connection.",
    "step3Item1": "Go to 'Basic Information'",
    "step3Item2": "Scroll to 'App-Level Tokens'",
    "step3Item3": "Click 'Generate Token and Scopes'",
    "step3Item4": "Name it (e.g., 'socket-mode')",
    "step3Item5": "Add 'connections:write' scope and click Generate",
    "step3Warning": "Keep this token secure. It provides full Socket Mode access.",
    "step4Title": "Validate & Finish",
    "step4Description": "Validate your tokens to ensure everything is configured correctly.",
    "inviteBotTitle": "Invite the bot to channels:",
    "step4Item1": "Open a Slack channel",
    "step4Item2": "Type /invite @avibe",
    "step4Item3": "The bot will now receive messages from this channel",
    "step4Tip": "You can also right-click a channel and select 'Add apps'."
  },
  "agentDetection": {
    "eyebrow": "Backends",
    "title": "Set up your agent backends",
    "subtitle": "We scan this machine for installed agents. Turn on the ones you have, and install anything that's missing.",
    "backendsLabel": "Agent backends",
    "detectedHelper": "Detected automatically on this machine — enable what you have, install anything missing.",
    "rescan": "Re-scan",
    "configureProvider": "Configure provider",
    "configureProviderTitle": "Configure {{name}}",
    "installAgentNamed": "Install {{name}}",
    "defaultBackend": "Default Backend",
    "cliPath": "CLI Path",
    "cliPathPlaceholder": "Path to {{name}} CLI...",
    "cliPathDetection": "CLI path detection and enablement",
    "recommended": "(recommended)",
    "permissionHint": "OpenCode requires permission config to skip approval prompts.",
    "permissionHintStrong": "Without this, OpenCode prompts for approval on every tool call. Avibe can't auto-reply, so the agent stalls.",
    "setupPermission": "Allow tool calls in opencode.json",
    "permissionGateHint": "Allow OpenCode tool calls above before you continue.",
    "installHint": "Agent not found. Click to install automatically.",
    "installAgent": "Install",
    "installing": "Installing...",
    "showOutput": "Show details"
  },
  "backendLifecycle": {
    "title": "Backend status",
    "statusReady": "Ready",
    "statusUpdating": "Updating",
    "statusDisabled": "Disabled",
    "statusError": "Not installed",
    "statusUpdateAvailable": "Update available",
    "currentVersion": "Current version",
    "latestVersion": "Latest version",
    "readyHint": "Running the latest release.",
    "updateHint": "Update available: {{from}} → {{to}}",
    "errorHint": "{{name}} CLI is not installed. Install it from this card to enable the backend.",
    "disabledHint": "Toggle this backend on in the card header to activate.",
    "upgrading": "Upgrading…",
    "upgradeNow": "Upgrade",
    "upgradeSuccess": "Upgrade complete",
    "upgradeFailed": "Upgrade failed",
    "reinstall": "Reinstall",
    "restart": "Restart",
    "restartSuccess": "Restart requested",
    "restartFailed": "Restart failed"
  },
  "channelList": {
    "eyebrow": "Groups",
    "title": "Group Settings",
    "subtitle": "Enable groups and configure routing for each group.",
    "refreshList": "Refresh List",
    "lastSynced": "Last synced {{time}}",
    "refreshingCache": "Refreshing in background",
    "refreshFailed": "Refresh failed; showing cached groups",
    "browseAll": "Browse All Groups",
    "showingAll": "Showing all workspace groups",
    "cantFindChannel": "Can't find your group?",
    "inviteBotHint": "Invite the bot to your channel first:\n1. Open the channel, click ⚙️ Settings → Integrations → Add apps\n2. Or type /invite @YourBotName in the channel",
    "discordInviteBotHint": "Add the bot to your guild and grant access to the channel.",
    "larkInviteBotHint": "Add the bot to a group chat: Open the group → Settings → Bots → Add Bot.",
    "telegramInviteBotHint": "Send a message from the Telegram group or forum to the bot first, then refresh this list.",
    "wechatInviteBotHint": "Send a message to your WeChat bot account to start a conversation.",
    "guild": "Guild",
    "guildPlaceholder": "Select a guild",
    "guildBrowse": "Viewing groups from",
    "guildAccess": "Guilds where the bot can work",
    "guildAccessCount": "{{count}} selected",
    "discordText": "Text",
    "discordNews": "News",
    "telegramForum": "Forum",
    "telegramSupergroup": "Supergroup",
    "telegramGroup": "Group",
    "telegramChat": "Chat",
    "telegramDiscoveryTitle": "Telegram uses discovered chats",
    "telegramDiscoveryInfo": "This page shows Telegram groups and forums that the bot has already seen from incoming messages. Direct messages stay hidden here.",
    "telegramDiscoveryStats": "{{visible}} visible chats · {{forum}} forums · {{hidden}} hidden DMs",
    "telegramDiscoveryEmptyTitle": "No Telegram chats discovered yet",
    "telegramDiscoveryEmptyDesc": "Send a message in any Telegram group or forum where the bot is present, then refresh this page.",
    "telegramLastSeen": "Last seen {{time}}",
    "enabledCount": "{{count}} enabled",
    "accessPolicy": "Access Policy",
    "accessPolicyHint": "Groups are enabled only when checked below.",
    "accessPolicyDiscord": "Guilds and groups are two separate switches",
    "accessPolicyHintDiscord": "First choose the Discord guilds where the bot can work, then enable specific groups and routing below.",
    "noChannelsFound": "No groups found. Check token or invite bot.",
    "noChannelsLoaded": "No groups loaded.",
    "addTokenFirst": "Add a bot token first to load groups.",
    "workingDirectory": "Working Directory",
    "useGlobalDefault": "Use global default",
    "backend": "Backend",
    "showMessageTypes": "Show Message Types",
    "showMessageTypesHint": "Control which message types are displayed in Slack:\n\n• System: Agent startup/status messages\n• Assistant: Agent responses and explanations\n• Toolcall: Tool execution details (one-line summary)\n\nNote: The agent's final result is always shown regardless of these settings.",
    "opencodeSettings": "OpenCode Settings",
    "claudeSettings": "Claude Settings",
    "codexSettings": "Codex Settings",
    "agent": "Agent",
    "model": "Model",
    "reasoningEffort": "Reasoning Effort",
    "claudeModelPlaceholder": "e.g. claude-sonnet-4-20250514",
    "codexModelPlaceholder": "e.g. o3",
    "reasoningLow": "Low",
    "reasoningMedium": "Medium",
    "reasoningHigh": "High",
    "reasoningMax": "Max",
    "reasoningXHigh": "XHigh",
    "searchModel": "Search model...",
    "settingsSaved": "Settings saved",
    "settingsSaveFailed": "Failed to save settings",
    "requireMention": "Require @Mention",
    "requireMentionOn": "Require @mention",
    "requireMentionOff": "Don't require @mention",
    "mentionStatusOn": "Require @",
    "mentionStatusOff": "Don't require @",
    "allChannelsTab": "All channels",
    "filterPlaceholder": "Filter groups…",
    "rescan": "Rescan",
    "showInactive": "Show inactive",
    "headerSummary": "All groups · {{active}} active · {{discovered}} discovered",
    "headerSummaryPlatform": "{{platform}} · {{active}} active · {{discovered}} discovered",
    "noChannelsForSearch": "No groups match your search.",
    "discordNeedsGuild": "Pick a Discord guild from the Discord tab to see channels here.",
    "platformDisabled": "Platform disabled — enable it in Settings to see groups."
  },
  "summary": {
    "eyebrow": "Summary",
    "title": "Review & Finish",
    "subtitle": "Confirm settings and start Avibe.",
    "mode": "Mode",
    "platform": "Platform",
    "slackBotToken": "Slack Bot Token",
    "slackAppToken": "Slack App Token",
    "discordBotToken": "Discord Bot Token",
    "telegramBotToken": "Telegram Bot Token",
    "larkAppId": "Lark App ID",
    "wechatBotToken": "WeChat Bot Token",
    "discordGuild": "Discord Guilds",
    "notSet": "Not set",
    "enabledAgents": "Enabled Agents",
    "channelsConfigured": "Groups Configured",
    "requireMention": "Require @Mention",
    "requireMentionHint": "Bot only responds when @mentioned in groups",
    "autoUpdate": "Auto Update",
    "autoUpdateHint": "Automatically install updates when system is idle",
    "usageTips": "Quick Start Guide",
    "tipStartCommand": "Use /start to begin",
    "tipStartCommandDesc": "Type /start in any enabled conversation to open the control panel.",
    "tipAgentSwitch": "Switch agents instantly",
    "tipAgentSwitchDesc": "Prefix your message with AgentName: to route to a specific agent. E.g., \"Plan: Design the API\"",
    "tipThread": "Thread = Session",
    "tipThreadDesc": "Each thread is an isolated session. Start multiple threads for parallel tasks.",
    "finishAndStart": "Finish & Start",
    "serviceRunning": "Avibe is running!",
    "goToDashboard": "Go to Dashboard",
    "bindCodeTitle": "Your First Bind Code",
    "bindCodeDesc": "Send this command to the bot in a DM to become the first admin:",
    "bindCodeCommand": "bind",
    "bindCodeCopied": "Copied!"
  },
  "dashboard": {
    "title": "Dashboard",
    "subtitle": "Live status of your local Avibe node.",
    "searchPlaceholder": "Quick search…",
    "heroTitle": "Avibe runtime overview",
    "runningTitle": "Avibe is running",
    "stoppedTitle": "Avibe is stopped",
    "startedAt": "Started {{time}} ({{relative}})",
    "levelHealthy": "Healthy",
    "levelAttention": "Attention",
    "metricPlatforms": "Active platforms",
    "metricPlatformsHint": "connected across the catalog",
    "metricGroups": "Active groups",
    "metricGroupsHint": "{{count}} discovered total",
    "metricUsers": "Bound users",
    "metricUsersHint": "authorized to access this node",
    "metricCloud": "Avibe Cloud",
    "metricCloudConnected": "Connected",
    "metricCloudConfigured": "Configured",
    "metricCloudDisconnected": "Off",
    "metricCloudHintConnected": "{{url}} is reachable through avibe.bot",
    "metricCloudHintConfigured": "Start the connector to make this node reachable",
    "metricCloudHintDisconnected": "Recommended: enable cloud access for this node",
    "metricHealth": "Health warnings",
    "metricHealthHealthy": "all checks green",
    "metricHealthIssues": "warnings or failures need review",
    "platformOverviewTitle": "Connected platforms",
    "platformOverviewSubtitle": "See which messaging platforms are live and jump to group routing where needed.",
    "platformGroupsHint": "{{active}} active / {{discovered}} discovered groups",
    "platformNoGroupsHint": "Direct messages only on this platform",
    "manageAll": "Manage all",
    "manageRoute": "Manage",
    "configure": "Configure",
    "connected": "Connected",
    "notConfigured": "Not configured",
    "recentActivityTitle": "Recent activity",
    "recentActivitySubtitle": "Latest runtime events from the main service log.",
    "recentActivityEmpty": "No recent service log events yet.",
    "openMessaging": "Open messaging settings",
    "groupsAndUsersTitle": "Groups and users",
    "groupsAndUsersHint": "Review group routing and user access separately now that they have dedicated pages.",
    "settingsShortcutTitle": "Settings shortcuts",
    "settingsShortcutHint": "Jump straight into backend defaults or service-level configuration.",
    "serviceStatus": "Service Status",
    "mode": "Mode",
    "platform": "Platform",
    "workspace": "Workspace",
    "gateway": "Gateway",
    "health": "Health",
    "allSystemsOperational": "All systems operational",
    "issuesDetected": "Issues detected",
    "globalPolicy": "Global Settings",
    "defaultBackend": "Default Backend",
    "slackWorkspace": "Slack Workspace",
    "messageHandling": "Message Handling",
    "requireMention": "Require Mention",
    "requireMentionHint": "Bot only responds when @mentioned",
    "ackMode": "Ack Mode",
    "ackModeHint": "How bot acknowledges received messages. Falls back to the next mode if the current one is unavailable.",
    "ackReaction": "👀 Reaction",
    "ackTyping": "✏️ Typing...",
    "ackMessage": "💬 Message",
    "audioTranscription": "Audio Transcription",
    "audioTranscriptionHint": "Transcribe supported audio attachments before sending the turn to the agent",
    "audioTranscriptionRequiresVibeCloud": "Pair this Avibe with Avibe Cloud before enabling audio transcription",
    "audioTranscriptionRequiresRemoteAccessTooltip": "Open Remote Access and pair this device with avibe.bot to enable audio transcription.",
    "audioTranscriptEcho": "Echo Transcript",
    "audioTranscriptEchoHint": "Send recognized text back to the chat when transcription succeeds",
    "errorRetryLimit": "Error Retry Limit",
    "errorRetryLimitHint": "Auto-retry with 'continue' when LLM stream errors occur (0 = no retry)",
    "showDuration": "Show Duration",
    "showDurationHint": "Display task elapsed time in result messages",
    "includeTimeInfo": "Include Current Time",
    "includeTimeInfoHint": "Prepend the current local time, including seconds and UTC offset, to messages sent to agents",
    "includeUserInfo": "Include User Info",
    "includeUserInfoHint": "Prepend [username<user_id>] to messages sent to agents",
    "replyEnhancements": "Quick-reply Buttons",
    "replyEnhancementsHint": "Allow agents to add clickable quick-reply buttons at the end of result messages",
    "showPagesPrompt": "Show Page Guidance",
    "showPagesPromptHint": "Tell agents when and how to use visual Show Pages. The vibe show CLI remains available when this is off.",
    "chatMessageFontSize": "Chat Message Font Size",
    "chatMessageFontSizeHint": "Font size for user and agent message bubbles in the Web UI chat",
    "slackLinkPreviews": "Suppress Slack Link Previews",
    "slackLinkPreviewsHint": "Disable Slack URL and media preview cards for messages sent by Avibe",
    "allowedChannels": "Allowed Groups",
    "consoleServer": "Console Server",
    "host": "Host",
    "port": "Port",
    "diagnostics": "Diagnostics",
    "logLevel": "Log Level",
    "configFile": "Config File",
    "logs": "Logs",
    "uiRestartMessage": "Saved. Restarting UI server...",
    "mainServiceRestarted": "Saved. Main service restarted.",
    "versionAndUpdate": "Version & Update",
    "currentVersion": "Current Version",
    "latestVersion": "Latest Version",
    "checkUpdate": "Check for Updates",
    "checking": "Checking...",
    "updateAvailable": "Update Available",
    "upgradeNow": "Upgrade Now",
    "upgrading": "Upgrading...",
    "upToDate": "You're up to date",
    "checkFailed": "Check failed",
    "upgradeSuccess": "Upgrade successful!",
    "upgradeFailed": "Upgrade failed",
    "updateHint": "Update from {{from}} to {{to}}",
    "restarting": "Restarting...",
    "autoUpdate": "Auto Update",
    "autoUpdateHint": "Auto-install when idle"
  },
  "doctor": {
    "title": "System Status",
    "copyReport": "Copy Report",
    "runChecks": "Run Checks",
    "passed": "Passed",
    "warnings": "Warnings",
    "failed": "Failed"
  },
  "logs": {
    "title": "System Logs",
    "autoRefreshOn": "Auto-refresh ON",
    "autoRefresh": "Auto-refresh",
    "searchPlaceholder": "Search logs by message, logger, or timestamp...",
    "allLevels": "All Levels",
    "error": "Error",
    "warning": "Warning",
    "info": "Info",
    "debug": "Debug",
    "all": "All",
    "entriesCount": "{{filtered}} of {{total}} entries",
    "totalInFile": "({{total}} total in file)",
    "allFiles": "All log files",
    "jumpToLatest": "Jump to latest",
    "loadingLogs": "Loading logs...",
    "noLogsAvailable": "No logs available",
    "noLogsMatch": "No logs match your filter",
    "sources": {
      "all": "All",
      "service": "Main service log",
      "serviceStdout": "Main service stdout",
      "serviceStderr": "Main service stderr",
      "uiStdout": "UI stdout",
      "uiStderr": "UI stderr"
    }
  },
  "language": {
    "switchLanguage": "Language",
    "en": "English",
    "zh": "Chinese"
  },
  "directoryBrowser": {
    "title": "Select Project Folder",
    "select": "Select",
    "cancel": "Cancel",
    "empty": "No subdirectories",
    "hiddenFiles": "Hidden files",
    "newFolder": "New Folder",
    "newFolderPlaceholder": "Folder name",
    "createHere": "Create new folder here…",
    "favorites": "Favorites",
    "favoritesHome": "Home",
    "favoritesDesktop": "Desktop",
    "favoritesDocuments": "Documents",
    "favoritesDownloads": "Downloads",
    "favoritesApplications": "Applications",
    "back": "Back",
    "forward": "Forward",
    "newFolderExists": "A folder with that name already exists.",
    "editPath": "Type a path",
    "editPathPlaceholder": "Absolute path, press Enter to go",
    "editPathDone": "Done",
    "pathNotFound": "Path doesn't exist or isn't readable."
  },
  "wechat": {
    "userBound": "Your WeChat account is automatically configured as the bot owner.",
    "noChannels": "WeChat uses direct messaging — no group configuration needed.",
    "setupComplete": "WeChat bot connected! Your account has been automatically configured.",
    "manageUserSettings": "Manage User Settings"
  },
  "userList": {
    "title": "Direct Messages",
    "subtitle": "Bound users from each IM platform · per-user routing & admin rights.",
    "noUsers": "No bound users yet. Create a bind code and share it with users.",
    "filterPlaceholder": "Filter users…",
    "allUsers": "All users",
    "showDisabled": "Show disabled",
    "settingsSaved": "User settings saved",
    "settingsSaveFailed": "Failed to save user settings",
    "admin": "Admin",
    "user": "User",
    "bot": "Bot",
    "boundAt": "Bound",
    "boundAgo": "bound {{ago}}",
    "removeUser": "Remove",
    "removeConfirm": "Remove this user? This cannot be undone.",
    "lastAdminDemoteWarning": "You are removing the last admin role. Continuing will put the bot into an 'unrestricted admin' state, where any bound user can access admin menus. Continue?",
    "lastAdminRemoveWarning": "You are removing the last admin user. Continuing will put the bot into an 'unrestricted admin' state, where any bound user can access admin menus. Continue?",
    "cannotRemoveLastAdmin": "Cannot remove the last admin",
    "adminToggled": "Admin status updated",
    "userRemoved": "User removed",
    "noUsersForSearch": "No users match your search.",
    "inheritsGlobal": "— inherits global —"
  },
  "bindCode": {
    "title": "Bind Codes",
    "badge": "BIND CODE",
    "inviteTitle": "Invite a new user from any platform",
    "inviteDescription": "Generate a one-time code. They DM your bot the code from Slack/Discord/Telegram/etc., and they're bound to this Avibe instance with the routing rules below.",
    "noActiveCode": "No active code",
    "noActiveHint": "Generate one to invite a user.",
    "activeCodeLabel": "ACTIVE CODE",
    "expiresIn": "expires in {{time}}",
    "noExpiry": "no expiry",
    "newCode": "New code",
    "createCode": "Create code",
    "revoke": "Revoke",
    "oneTime": "One-time",
    "expiring": "Expiring",
    "active": "Active",
    "used": "Used",
    "expired": "Expired",
    "inactive": "Inactive",
    "usedBy": "{{count}} used",
    "expiresAt": "Expires {{date}}",
    "copy": "Copy",
    "copied": "Copied!",
    "delete": "Delete",
    "generate": "Generate",
    "codeType": "Type",
    "expirationDate": "Expiration date",
    "created": "Bind code created",
    "deleted": "Bind code deleted",
    "noCodes": "No bind codes yet. Create one to get started.",
    "usageTitle": "How to use a bind code",
    "usageHint": "Share an active code with the user, then ask them to DM the bot with `bind <code>`. `/bind <code>` still works too.",
    "viewUnavailable": "Unavailable ({{count}})",
    "viewMore": "+ {{count}} more",
    "unavailableTitle": "Unavailable Bind Codes",
    "allCodesTitle": "All Bind Codes",
    "noAvailableCodes": "No active bind codes. Create a new code to start binding users.",
    "noUnavailableCodes": "No unavailable bind codes.",
    "close": "Close"
  },
  "agents": {
    "title": "Agents",
    "subtitle": "{{count}} agents registered across all backends.",
    "showDisabled": "Show disabled",
    "statusEnabled": "enabled",
    "statusDisabled": "disabled",
    "newAgent": "New agent",
    "import": "Import",
    "importFromClaude": "Import from Claude",
    "importFromCodex": "Import from Codex",
    "importFromOpenCode": "Import from OpenCode",
    "importSuccess": "Imported {{imported}}, skipped {{skipped}}.",
    "importFailed": "Import failed: {{error}}",
    "importNoneFound": "No {{backend}} agents found on disk to import.",
    "renameSuccess": "Agent renamed",
    "renameKeptOld": "Agent renamed (old one kept due to references)",
    "searchPlaceholder": "Search agents…",
    "backendFilter": "Backend",
    "backendAll": "All",
    "noSearchMatch": "No matching agents.",
    "noConfig": "No model or system prompt configured",
    "empty": "No agents yet. Create one to start a conversation.",
    "selectPrompt": "Select an agent to view its configuration.",
    "makeDefault": "Make default",
    "deleteConfirm": "Delete agent \"{{name}}\"? This cannot be undone.",
    "deleteInUse": "Agent \"{{name}}\" is currently in use by one or more channels and cannot be deleted.",
    "detail": {
      "enabled": "Enabled",
      "enabledHint": "Disabling keeps the agent in the registry but excludes it from new sessions; running sessions are unaffected.",
      "defaultTitle": "Default agent",
      "defaultHint": "New chats and IM messages without an explicit agent route to this one.",
      "defaultActive": "Default",
      "setDefault": "Set as default",
      "defaultNeedsEnabled": "Enable the agent before making it the default.",
      "defaultSet": "{{name}} is now the default agent.",
      "name": "Name",
      "description": "Description",
      "descriptionPlaceholder": "What this agent is for…",
      "backend": "Backend",
      "backendLocked": "creation-time only · locked",
      "model": "Model",
      "modelPlaceholder": "Pick or type a model",
      "modelEmpty": "No matches — you can type a custom value.",
      "modelDefault": "Backend default",
      "effort": "Reasoning effort",
      "systemPrompt": "System prompt",
      "systemPromptCount": "~{{count}} tokens",
      "systemPromptExpand": "Expand editor",
      "systemPromptEditorHint": "Write the full system prompt with live Markdown preview.",
      "systemLocked": "System agents cannot be deleted. You can still adjust model, effort, and system prompt.",
      "run": "Run",
      "nameLocked": "Used as the reference id · locked after create"
    },
    "runDialog": {
      "title": "Open a chat with this agent",
      "description": "Pick a project. A new session is created under it and the chat opens immediately.",
      "projectLabel": "Project",
      "noProject": "No projects yet — add one from the sidebar + button first.",
      "cancel": "Cancel",
      "open": "Open chat",
      "opening": "Creating session…"
    },
    "create": {
      "title": "New Agent",
      "body": "Pick a backend, name the agent, and fine-tune model and effort. Backend cannot be changed after creation.",
      "backend": "Backend",
      "name": "Name",
      "namePlaceholder": "Agent name (e.g. reviewer)",
      "description": "Description",
      "descriptionPlaceholder": "What this agent is for…",
      "model": "Model",
      "modelPlaceholder": "e.g. claude-sonnet-4-6",
      "effort": "Effort",
      "systemPrompt": "System prompt",
      "systemPromptHint": "Optional",
      "systemPromptPlaceholder": "Optional. Prepended to every conversation that uses this agent.",
      "submit": "Create agent"
    }
  },
  "editor": {
    "modeLabel": "Editor mode",
    "edit": "Edit",
    "preview": "Preview",
    "markdownHint": "Markdown supported",
    "previewEmpty": "Nothing to preview yet."
  },
  "agentsMd": {
    "title": "Edit AGENTS.md",
    "description": "Edit this project's AGENTS.md — the project-level instructions handed to the agent.",
    "placeholder": "Write this project's AGENTS.md in Markdown…",
    "loading": "Loading…",
    "loadedFromClaude": "This project has no AGENTS.md yet — loaded CLAUDE.md's content as a starting point. Saving will write AGENTS.md.",
    "symlinkToggle": "Migrate CLAUDE.md into AGENTS.md and symlink them to stay in sync (recommended)",
    "symlinkMigrateWarning": "The current CLAUDE.md file will be deleted and replaced with a symlink to AGENTS.md.",
    "saved": "AGENTS.md saved",
    "savedSymlinkFailed": "AGENTS.md saved, but the symlink could not be created."
  },
  "projectSettings": {
    "title": "Project settings",
    "description": "Configure where this project runs and which Agent its new sessions use.",
    "workdir": {
      "label": "Working directory",
      "hint": "The Agent works inside this directory.",
      "unset": "No folder configured"
    },
    "defaultAgent": {
      "label": "Default Agent",
      "hint": "New sessions in this project start with this Agent, model, and reasoning effort. Leave it on \"Follow global default\" to use your global default Agent instead. Changing it never affects existing sessions.",
      "followGlobal": "Follow global default"
    },
    "guidance": {
      "label": "Project guidance prompt",
      "button": "Edit project guidance prompt",
      "hint": "Project-level instructions (AGENTS.md) handed to the Agent for every session in this project.",
      "noFolder": "Add a folder to this project to edit its guidance prompt."
    }
  },
  "globalPrompts": {
    "button": "Global prompts",
    "title": "Global prompts",
    "description": "Edit each backend's global instructions file — applied ahead of every agent's system prompt on this machine.",
    "placeholder": "Write global instructions for this backend in Markdown…",
    "tipEffect": "Prepended to the system prompt of every {{backend}} agent. New sessions pick it up.",
    "missingHint": "this file doesn't exist yet — saving creates it",
    "readError": "Couldn't read this file (not valid UTF-8). Fix it on disk before editing it here.",
    "save": "Save",
    "sync": "Sync to all backends",
    "syncConfirm": "Overwrite all three backends' global prompt files with {{backend}}'s current content?",
    "saved": "Saved {{backend}}'s global prompt.",
    "synced": "Synced to all backends.",
    "discardConfirm": "You have unsaved changes. Close and discard them?"
  },
  "skills": {
    "title": "Skills",
    "subtitle": "Manage global and project skills across your agent backends · powered by askill.",
    "scopeGlobal": "Global",
    "scopeProject": "Project",
    "searchPlaceholder": "Search installed skills…",
    "searchProjectPlaceholder": "Search this project's skills…",
    "backendFilter": "Backend",
    "backendAll": "All",
    "browseRegistry": "Browse registry",
    "addSkill": "Add skill",
    "empty": "No skills installed yet. Add one from GitHub, a .zip, or the registry.",
    "noSearchMatch": "No matching skills.",
    "notInstalled": "askill isn't installed",
    "notInstalledHint": "askill powers the Skills page. Install it now, or it installs automatically when Avibe updates.",
    "installAskill": "Install askill",
    "installing": "Installing…",
    "installFailed": "Could not install askill.",
    "projectNoFolder": "This project has no folder configured, so it has no project-scoped skills — showing global skills only.",
    "removeConfirm": "Remove skill \"{{name}}\"? This unlinks it from the selected scope.",
    "removeSuccess": "Removed {{name}}.",
    "addSuccess": "Installed {{count}} skill(s).",
    "updateSuccess": "Updated {{name}}.",
    "scopeGlobalPath": "~/.agents/skills · shared across all projects",
    "projectSectionLocal": "Project skills",
    "projectSectionLocalHint": "installed in this repo only",
    "projectSectionGlobal": "Also available · inherited from global",
    "projectSectionGlobalHint": "manage these in the Global tab",
    "globalBadge": "Global",
    "updateBadge": "Update",
    "globalAlsoAvailable": "Global skills are available here too",
    "picker": {
      "title": "Switch project",
      "openFolder": "Open a project folder…"
    },
    "detail": {
      "subtitleGlobal": "Agent Skill · installed globally",
      "subtitleProject": "Agent Skill · {{project}}",
      "source": "Source",
      "viewOnGithub": "View on GitHub",
      "quality": "AI quality",
      "availableTo": "Available to",
      "commands": "Commands",
      "openSkillMd": "Open SKILL.md",
      "remove": "Remove",
      "update": "Update"
    },
    "addDialog": {
      "title": "Add a skill",
      "subtitle": "From a GitHub repo, or upload a local .zip package.",
      "githubTab": "GitHub URL",
      "zipTab": "Upload .zip",
      "urlLabel": "GitHub URL or slug",
      "urlPlaceholder": "github.com/owner/repo or gh:owner/repo@skill",
      "fetch": "Fetch",
      "package": "Skill package",
      "dropzoneHint": "Drag & drop a .zip here, or click to choose one.",
      "localNote": "Unpacked and installed locally via askill — never sent to a third-party service.",
      "replace": "Replace",
      "found": "Found {{count}} skill(s) · select to install",
      "installTo": "Install to",
      "backends": "Install for backends",
      "cancel": "Cancel",
      "install": "Install {{count}} skill(s)",
      "installing": "Installing…",
      "fetchFirst": "Enter a source and fetch to see its skills."
    },
    "browse": {
      "title": "Browse the askill registry",
      "subtitle": "AI-reviewed skills from askill.sh.",
      "searchPlaceholder": "Search skills…",
      "resultsCount": "{{count}} results",
      "showing": "Showing {{shown}} of {{total}} · ranked by AI score",
      "tagAll": "All",
      "add": "Add",
      "installed": "Installed",
      "done": "Done",
      "empty": "No skills match your search."
    }
  },
  "harness": {
    "title": "Harness",
    "subtitle": "Scheduled tasks, watches, webhooks, and the run history of all three.",
    "soon": "soon",
    "create": "Create",
    "searchPlaceholder": "Search…",
    "statusFilter": {
      "all": "All",
      "enabled": "Enabled only",
      "disabled": "Disabled only"
    },
    "filtered": "{{shown}}/{{total}}",
    "selectPrompt": "Select a row to view its full configuration.",
    "emptyTasks": "No scheduled tasks. Ask an agent to create one.",
    "emptyWatches": "No watches running. Ask an agent to start one.",
    "emptyRuns": "No runs yet. They appear here once a task or watch fires.",
    "webhooksSoon": "Webhooks are coming soon",
    "webhooksSoonBody": "Inbound HTTP triggers will land in a follow-up release. Tasks and watches cover scheduled and event-driven runs today.",
    "unknownSchedule": "unknown schedule",
    "schedule": {
      "cron": "cron · {{value}}",
      "oneShot": "one-shot · {{value}}"
    },
    "pageLabel": "page {{page}}",
    "runtime": {
      "running": "Running",
      "paused": "Paused",
      "idle": "Idle",
      "enabled": "Enabled",
      "disabled": "Disabled"
    },
    "tabs": {
      "tasks": "Tasks",
      "watches": "Watches",
      "webhooks": "Webhooks",
      "runs": "Runs"
    },
    "detail": {
      "schedule": "Schedule",
      "agent": "Agent",
      "message": "Message",
      "lastRun": "Last run",
      "id": "ID",
      "command": "Command",
      "cwd": "Working directory",
      "mode": "Mode",
      "followUp": "Follow-up message",
      "runtime": "Runtime",
      "lastError": "Last error",
      "type": "Type",
      "definition": "Definition",
      "result": "Result",
      "error": "Error",
      "timing": "Timing",
      "nextRun": "Next run",
      "session": "Session",
      "sessionPolicy": "Session mode",
      "delivery": "Delivery",
      "openInAgents": "Open in Agents",
      "agentInherit": "Inherits default agent",
      "sessionNone": "No bound session",
      "effort": "effort {{value}}"
    },
    "sessionPolicy": {
      "createPerRun": "New session each run",
      "createOnce": "Create once, then reuse",
      "existing": "Reuse the same session"
    },
    "delivery": {
      "channel": "Channel",
      "thread": "Thread",
      "session": "Default · session location"
    },
    "row": {
      "enable": "Enable",
      "disable": "Disable",
      "delete": "Delete",
      "deleteConfirmTask": "Delete \"{{name}}\"? It will stop running.",
      "deleteConfirmWatch": "Delete \"{{name}}\"? The watch will stop immediately."
    },
    "createDialog": {
      "title": "Talk to an agent to set up background work",
      "subtitle": "Writing cron is the tool era; describing intent is the colleague era.",
      "body": "Scheduled tasks, watches, and (soon) webhooks all come from a chat with an agent. The agent translates your intent into vibe task add / vibe watch add arguments so you never have to remember cron syntax.",
      "example": "Example: \"Every weekday at 9:30am, summarize yesterday's #ops activity and post to #ops.\" The agent picks the cron, builds the prompt, and binds it to this project.",
      "projectLabel": "Create in which project",
      "noProject": "No projects yet — add one from the sidebar + button first.",
      "cancel": "Cancel",
      "open": "Open chat and walk me through",
      "opening": "Creating session…",
      "kindTask": "Scheduled task",
      "kindWatch": "Watch",
      "promptTask": "Help me create a scheduled task. What I want: [describe here, e.g. \"every weekday at 9:30am summarize yesterday's PR comments\"]. Once parameters look right, run vibe task add and bind it to this project.",
      "promptWatch": "Help me create a watch. I want to wait for: [describe here, e.g. \"CI workflow #1234 to finish\"]. Notify me when the condition is met. Once parameters look right, run vibe watch add."
    }
  },
  "chat": {
    "back": "Back",
    "untitled": "Untitled session",
    "titlePlaceholder": "Session title",
    "pickAgent": "Pick an agent",
    "noAgents": "No enabled agents. Create one on the Agents page.",
    "modelPlaceholder": "Model override",
    "changesPersist": "changes apply on the next reply",
    "sessionOverrideHint": "New sessions inherit the project's defaults; changes here apply immediately and only to this session.",
    "notFound": "Session not found.",
    "missingSessionId": "Missing session id in the URL.",
    "transcriptEmpty": "Type a message below to start the conversation",
    "scrollToBottom": "Scroll to latest",
    "streaming": "Streaming",
    "thinking": "Thinking…",
    "notifyLabel": "Notify",
    "collapse": "Collapse",
    "turnInProgress": "A turn is already running — wait for the reply.",
    "stopFailed": "Couldn't reach the agent to stop it — it may still be running.",
    "source": {
      "scheduled": "Scheduled task",
      "watch": "Watch",
      "webhook": "Webhook",
      "harness": "Automated"
    },
    "picker": {
      "agent": "Agent",
      "model": "Model",
      "effort": "Effort",
      "newAgent": "New agent",
      "noModels": "No models found",
      "effortOptions": {
        "minimal": "Minimal",
        "low": "Low",
        "medium": "Medium",
        "high": "High",
        "xhigh": "Extra High",
        "max": "Max"
      }
    },
    "compose": {
      "placeholder": "Type a message…",
      "placeholderBusy": "Type to queue while the agent works…",
      "hint": "Enter to send",
      "send": "Send",
      "queueSend": "Send to queue",
      "sending": "Sending…",
      "stop": "Stop",
      "attach": "Attach files",
      "voice": "Voice input",
      "stopRecording": "Stop recording",
      "cancelRecording": "Cancel recording",
      "removeAttachment": "Remove",
      "dropOverlay": "Drop files to attach"
    },
    "media": {
      "preview": "Preview",
      "download": "Download"
    },
    "viewer": {
      "close": "Close",
      "previous": "Previous",
      "next": "Next",
      "loading": "Loading…",
      "error": "Couldn't load this file.",
      "tooLarge": "File too large to preview — download it instead.",
      "csvTruncated": "Showing the first {{count}} rows",
      "csvColsTruncated": "Showing {{shown}} of {{total}} columns"
    },
    "queue": {
      "title": "Queued · {{count}}",
      "sendNow": "Send now",
      "remove": "Remove from queue"
    }
  }
}
