a6bd33bcff
Workspace sessions (docs/plans/desktop-parity, phases 1-5 and 7): - sessions.lane_id: a workspace lists only the sessions its panes held, stamped by bindRunSession (first writer wins, nested `claude -p` excluded); GET /api/sessions?lane=&archived= - session row state dot, double-click rename, archive (sessions.archived_at, hides only); the activity bar's duplicate Sessions tab removed - Fork beside Resume (--fork-session, Claude only), Ctrl/Cmd+click a live session opens it in a second pane, a diff line's comment is pasted into the workspace's last-focused pane (lib/panePaste.ts) dashboard_runs stability: - a pane's previous run is archived as <pane>@<started_at> instead of being overwritten by INSERT OR REPLACE - a run is flagged abandoned only once its tmux session is gone, at boot and on the run-heal beat (panes outlive a server restart) UI: - sidebar: no footer, language or theme block; small collapse button in the brand corner; version + update check in the connection details modal, a status-bar dot while a release is out; language in Settings -> General - one Switch component for every switch, the themed Checkbox for every checkbox (no native checkboxes) Also: AI Tools catalog trimmed to 10 built-ins (custom-file prompt modes tested through fixtures), and the workspace plans under docs/plans/ (the multi-user server plan lives in the AgentHub-Server repo).
724 lines
33 KiB
JSON
724 lines
33 KiB
JSON
{
|
|
"title": "Settings",
|
|
"subtitle": "Manage appearance, AI tools, notifications and data",
|
|
"exportData": "Export Data",
|
|
"acrossSessions": "Across all tracked sessions",
|
|
"basedOnUsage": "Based on per-model token usage",
|
|
"sagi": {
|
|
"title": "Sagi companion",
|
|
"description": "A floating mascot that reacts to your live sessions.",
|
|
"enable": "Show Sagi",
|
|
"enableDesc": "Display the corner companion across the dashboard (⌘B to open)"
|
|
},
|
|
"pricing": {
|
|
"title": "Model Pricing",
|
|
"description": "Rates per million tokens (USD). Use % as wildcard in patterns. Some models have a time-limited introductory rate (shown in violet); usage on or before its cutoff date is billed at that rate, and usage after it at the standard rate.",
|
|
"introNote": "Intro ${{input}}/${{output}} through {{until}}",
|
|
"introRatesTitle": "Introductory rates",
|
|
"introRatesHint": "Leave the date empty for no promo",
|
|
"introUntil": "Through (date)",
|
|
"introUntilInvalid": "Introductory cutoff must be a YYYY-MM-DD date",
|
|
"resetConfirm": "Confirm Reset",
|
|
"resetDefaults": "Reset Defaults",
|
|
"resetResult": "Reset to {{count}} default rules",
|
|
"addModel": "Add Model",
|
|
"pattern": "Pattern",
|
|
"validationRequired": "Pattern and display name are required",
|
|
"lastUpdated": "Last updated: ",
|
|
"tooltip": {
|
|
"title": "How model pricing works",
|
|
"howItWorks": "How it works",
|
|
"howItWorksBody": "When a session reports usage, the dashboard finds the first pricing rule whose pattern matches the model id and multiplies (input tokens / 1M) and (output tokens / 1M) by the rates below to compute cost. Rules are evaluated top-to-bottom - the first match wins.",
|
|
"patternsTitle": "Pattern syntax",
|
|
"patternsBody": "Patterns are SQL-style globs. % is a wildcard that matches any characters. For example: claude-opus-4-7% matches every model id that starts with claude-opus-4-7 (e.g. claude-opus-4-7, claude-opus-4-7-20260101). claude-%-haiku matches any haiku variant. An exact id like claude-sonnet-4-6 only matches itself.",
|
|
"apiPricing": "Reference only - API rates",
|
|
"apiPricingBody": "These are pay-as-you-go API rates. If you use Claude Code on a subscription plan (Pro, Max, Team, or Enterprise), your actual cost is a flat monthly fee, not per-token - so these figures will usually be higher than what you really pay. Treat the costs here as a usage estimate for reference, not a bill.",
|
|
"synced": "Prices are filled in automatically",
|
|
"syncedBody": "Every current Claude, OpenAI and Gemini model is priced from LiteLLM's public price list, checked once a day, as is any other model the moment a session uses it. Rows marked Auto follow that list when a rate changes; a row you edit becomes yours and is never touched again, and a row you delete stays deleted. Already-stored sessions keep the price that was applied at ingest time.",
|
|
"apiPricingOtherBody": "These are pay-as-you-go API rates. If you use this CLI on a subscription plan, your actual cost is a flat fee, not per-token - so these figures will usually be higher than what you really pay. Treat them as a usage estimate, not a bill."
|
|
},
|
|
"cacheWrite5m": "Cache Write (5m)",
|
|
"cacheWrite1h": "Cache Write (1h)",
|
|
"fastInput": "Fast Input",
|
|
"fastOutput": "Fast Output",
|
|
"showAll": "Show all models ({{count}} more)",
|
|
"empty": {
|
|
"claude": "No Claude model prices. Reset Defaults restores them.",
|
|
"openai": "No OpenAI model prices yet. They are added automatically from LiteLLM's price list once a Codex session uses a model, or add one yourself.",
|
|
"google": "No Gemini model prices yet. They are added automatically from LiteLLM's price list once an Antigravity session uses a model, or add one yourself."
|
|
},
|
|
"placeholders": {
|
|
"claude": {
|
|
"pattern": "claude-opus-4%",
|
|
"name": "Claude Opus 4"
|
|
},
|
|
"openai": {
|
|
"pattern": "gpt-5%",
|
|
"name": "GPT 5"
|
|
},
|
|
"google": {
|
|
"pattern": "gemini-3.8-flash%",
|
|
"name": "Gemini 3.8 Flash"
|
|
}
|
|
},
|
|
"autoBadge": "Auto",
|
|
"autoBadgeTitle": "Kept at the published rate automatically (LiteLLM's price list, checked daily). Edit it to keep your own rate."
|
|
},
|
|
"claudeHome": {
|
|
"title": "CLAUDE_HOME",
|
|
"description": "Root directory for Claude Code session data. Changing this updates the scan path for transcripts and imports immediately.",
|
|
"placeholder": "/path/to/claude-home",
|
|
"routersMissing": "Saved. These workspaces name an AI Router profile the new home does not have, and start on Native until it is added there or they are re-pointed: {{lanes}}"
|
|
},
|
|
"hooks": {
|
|
"title": "Hook Configuration",
|
|
"description": "Claude Code hooks forward events to the dashboard in real time.",
|
|
"allInstalled": "All hooks installed",
|
|
"incomplete": "Hooks incomplete",
|
|
"reinstall": "Reinstall Hooks",
|
|
"success": "Hooks installed successfully",
|
|
"failed": "Hook installation failed"
|
|
},
|
|
"lanesSection": {
|
|
"title": "Workspaces",
|
|
"description": "Machine-wide workspace housekeeping.",
|
|
"runHousekeeping": "Run housekeeping",
|
|
"dryRun": "Dry run",
|
|
"gcResult": "Reaped {{reaped}} process(es), capped {{capped}} log(s)"
|
|
},
|
|
"notifications": {
|
|
"awaitingInput": "Claude needs confirmation",
|
|
"blocked": "Permission blocked",
|
|
"description": "Browser notifications for important events. Requires permission.",
|
|
"disabledInfo": "Notifications are disabled - enable to get alerts for session events",
|
|
"enable": "Enable Browser Notifications",
|
|
"granted": "Permission granted",
|
|
"newSession": "New session starts",
|
|
"notifyWhen": "Notify me when...",
|
|
"required": "Permission required",
|
|
"sendTest": "Send Test Notification",
|
|
"sessionComplete": "Session completes",
|
|
"sessionError": "Session errors",
|
|
"subagentSpawned": "Subagent spawned",
|
|
"testBlocked": "The browser has not granted notification permission.",
|
|
"testBody": "Notifications are working!",
|
|
"testFailed": "Nothing could be shown.",
|
|
"testLocal": "Your browser has no push subscription, so this was shown locally. Web Push needs a secure origin (localhost or HTTPS) and a registered service worker.",
|
|
"testSent": "Sent via push — check your notification centre.",
|
|
"testTitle": "Agent Monitor",
|
|
"title": "Notifications",
|
|
"turnComplete": "Claude finishes a turn",
|
|
"sound": {
|
|
"title": "Sound",
|
|
"description": "Played with every notification shown. Each type below can pick its own.",
|
|
"preview": "Play",
|
|
"useDefault": "Default",
|
|
"none": "None",
|
|
"chime": "Chime",
|
|
"pop": "Pop",
|
|
"alert": "Alert",
|
|
"forType": "Sound for this type"
|
|
}
|
|
},
|
|
"import": {
|
|
"title": "Import History",
|
|
"description": "Bring existing Claude Code sessions into the dashboard. Token counts, per-model cost, compactions, subagents, tool uses, and turn durations are reconstructed from the original JSONL transcripts - identical to how live sessions are captured.",
|
|
"accuracyNote": "Re-running is safe. Sessions are deduplicated by session ID, and compaction baselines ensure token totals never double-count.",
|
|
"supportedFiles": "Supported inputs: .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz",
|
|
"instructions": "How to gather your history",
|
|
"stepLocate": "1. Locate your Claude Code history",
|
|
"stepLocateBody": "Every Claude Code session is stored as a JSONL transcript under the projects folder. Each subfolder is named after the working directory where the session started (slashes replaced with dashes).",
|
|
"stepArchive": "2. Bundle it for transfer (optional)",
|
|
"stepArchiveBody": "To move history from another machine, archive the whole folder first, then copy it over (AirDrop, scp, USB, cloud storage):",
|
|
"stepChoose": "3. Pick an import mode below",
|
|
"stepChooseBody": "Rescan the default location, point at any folder you've extracted history into, or upload files/archives directly.",
|
|
"stepVerify": "4. Verify tokens and cost",
|
|
"stepVerifyBody": "After import, open Analytics → Cost to confirm the breakdown. Re-importing the same session is always safe.",
|
|
"defaultLocation": "Default location on this machine",
|
|
"locationFound": "Folder found",
|
|
"locationMissing": "Folder not found",
|
|
"projectsLabel": "projects",
|
|
"jsonlLabel": "JSONL files",
|
|
"modeRescan": "Rescan default folder",
|
|
"modeRescanDesc": "Re-read ~/.claude/projects and import anything new.",
|
|
"modeFolder": "Scan a folder",
|
|
"modeFolderDesc": "Scan any directory on this machine for JSONL transcripts (walks subfolders).",
|
|
"modeUpload": "Upload files",
|
|
"modeUploadDesc": "Drop JSONL files or an archive (.zip / .tar.gz) directly into the browser.",
|
|
"modeBackup": "Restore backup",
|
|
"modeBackupDesc": "Import a dashboard export (.json) from Export data — merge another machine's history in.",
|
|
"backupHint": "Drop an export .json here or click to select",
|
|
"backupSub": "The file produced by the Export data button (top of Settings)",
|
|
"runRestore": "Restore",
|
|
"backupResult": {
|
|
"title": "Restore complete",
|
|
"sessionsImported": "Sessions added: {{count}}",
|
|
"sessionsSkipped": "Already present: {{count}}",
|
|
"events": "Events: {{count}}",
|
|
"pricing": "Pricing rules: {{count}}",
|
|
"detail": "{{agents}} agents · {{workflows}} workflows · {{runs}} runs · {{rules}} alert rules"
|
|
},
|
|
"folderPlaceholder": "/absolute/path/to/claude-history",
|
|
"folderHelper": "Absolute path. Tilde (~) is expanded. Subfolders are scanned recursively.",
|
|
"runRescan": "Rescan Now",
|
|
"runScan": "Scan Folder",
|
|
"runUpload": "Upload & Import",
|
|
"dropzoneHint": "Drag files here or click to select",
|
|
"dropzoneSub": "Accepts .jsonl, .meta.json, .zip, .tar, .tar.gz, .tgz, .gz",
|
|
"filesSelected": "{{count}} file(s) selected",
|
|
"clearSelection": "Clear",
|
|
"copy": "Copy",
|
|
"copied": "Copied",
|
|
"progress": {
|
|
"scan": "Scanning directory...",
|
|
"extract": "Extracting archives ({{processed}}/{{total}})...",
|
|
"parse": "Parsing transcripts ({{processed}}/{{total}})...",
|
|
"complete": "Import complete",
|
|
"error": "Import failed"
|
|
},
|
|
"result": {
|
|
"imported": "Imported: {{count}}",
|
|
"backfilled": "Enriched existing: {{count}}",
|
|
"skipped": "Already up to date: {{count}}",
|
|
"errors": "Errors: {{count}}",
|
|
"filesScanned": "Files scanned: {{count}}",
|
|
"title": "Last import result"
|
|
},
|
|
"errors": {
|
|
"noFiles": "No files selected",
|
|
"noJsonl": "No .jsonl files were found in the uploaded content",
|
|
"pathRequired": "Path is required",
|
|
"pathInvalid": "Path must be absolute",
|
|
"pathNotFound": "Path does not exist",
|
|
"pathNotDir": "Path is not a directory",
|
|
"generic": "Import failed: {{message}}"
|
|
}
|
|
},
|
|
"data": {
|
|
"title": "Data Management",
|
|
"description": "Database info, import/export, and cleanup.",
|
|
"dbOverview": "Database Overview",
|
|
"dbSize": "DB Size",
|
|
"loadingDb": "Loading database info...",
|
|
"sessionCleanup": "Session Cleanup",
|
|
"cleanupDesc": "Abandon stale sessions and purge old data",
|
|
"abandonAfter": "Abandon stale active sessions older than",
|
|
"purgeAfter": "Purge completed/errored sessions older than",
|
|
"confirmCleanup": "Confirm Cleanup",
|
|
"runCleanup": "Run Cleanup",
|
|
"nothingToClean": "Nothing to clean up",
|
|
"abandonedResult": " sessions abandoned",
|
|
"purgedResult": " sessions purged ({{events}} events, {{agents}} agents)"
|
|
},
|
|
"danger": {
|
|
"title": "Danger Zone",
|
|
"description": "Irreversible actions that delete data permanently",
|
|
"warning": "This will delete all sessions, agents, events, and token data. Are you sure?",
|
|
"yesClearAll": "Yes, Clear All",
|
|
"clearAllData": "Clear All Data",
|
|
"clearedResult": "Cleared {{count}} rows"
|
|
},
|
|
"about": {
|
|
"title": "About",
|
|
"description": "Server runtime information.",
|
|
"release": "Release",
|
|
"uiBuild": "UI build v{{version}} (rebuild client to match)",
|
|
"uptime": "Uptime",
|
|
"nodejs": "Node.js",
|
|
"platform": "Platform",
|
|
"wsClients": "WS Clients",
|
|
"loadingInfo": "Loading server info..."
|
|
},
|
|
"tables": {
|
|
"sessions": "sessions",
|
|
"agents": "agents",
|
|
"events": "events",
|
|
"sessionsWithCost": "sessions with cost",
|
|
"pricingRules": "pricing rules"
|
|
},
|
|
"messages": {
|
|
"failedLoad": "Failed to load",
|
|
"failedSave": "Failed to save",
|
|
"failedDelete": "Failed to delete",
|
|
"unknownError": "Unknown",
|
|
"actionFailed": "Error: {{message}}"
|
|
},
|
|
"webhooks": {
|
|
"title": "Webhook Notifications",
|
|
"description": "Forward fired alerts to Slack, Discord, Microsoft Teams, or any HTTP endpoint. Delivery is automatic, retried on failure, and never blocks monitoring.",
|
|
"count_one": "{{count}} target",
|
|
"count_other": "{{count}} targets",
|
|
"add": "Add Webhook",
|
|
"loading": "Loading webhooks…",
|
|
"empty": "No webhooks configured. Add one to forward alerts to Slack, Discord, Teams, or a custom endpoint.",
|
|
"scopedTo_one": "{{count}} rule",
|
|
"scopedTo_other": "{{count}} rules",
|
|
"enabled": "Enabled",
|
|
"test": "Test",
|
|
"edit": "Edit",
|
|
"delete": "Delete",
|
|
"confirmDelete": "Confirm",
|
|
"testOk": "Delivered (HTTP {{status}})",
|
|
"testFail": "Failed: {{error}}",
|
|
"addTitle": "New Webhook",
|
|
"editTitle": "Edit Webhook",
|
|
"fieldName": "Name",
|
|
"fieldNamePlaceholder": "e.g. Team Slack #alerts",
|
|
"fieldType": "Type",
|
|
"type": {
|
|
"slack": "Slack",
|
|
"discord": "Discord",
|
|
"teams": "Microsoft Teams",
|
|
"generic": "Generic (custom JSON)"
|
|
},
|
|
"fieldUrl": "Webhook URL",
|
|
"urlKeepHint": "leave blank to keep current",
|
|
"urlKeepPlaceholder": "•••••••• (unchanged)",
|
|
"urlPlaceholder": {
|
|
"slack": "https://hooks.slack.com/services/…",
|
|
"discord": "https://discord.com/api/webhooks/…",
|
|
"teams": "https://outlook.office.com/webhook/…",
|
|
"generic": "https://example.com/webhook"
|
|
},
|
|
"fieldSecret": "Signing secret (optional)",
|
|
"secretPlaceholder": "HMAC-SHA256 secret",
|
|
"secretKeepPlaceholder": "•••••••• (leave blank to keep)",
|
|
"secretHint": "When set, requests are signed with an X-Webhook-Signature header.",
|
|
"fieldHeaders": "Custom headers (optional)",
|
|
"replaceHeaders": "Replace headers",
|
|
"headerKey": "Header",
|
|
"headerValue": "Value",
|
|
"addHeader": "Add header",
|
|
"scopeAll": "Receive alerts from all rules",
|
|
"enabledOnSave": "Enabled",
|
|
"save": "Save",
|
|
"create": "Create",
|
|
"cancel": "Cancel",
|
|
"urlOptional": "optional override",
|
|
"urlAuto": "URL is set automatically from the credentials below.",
|
|
"deleteTitle": "Delete webhook?",
|
|
"deleteMessage": "Delete \"{{name}}\"? Fired alerts will stop being delivered to this target. This cannot be undone.",
|
|
"guideToggle": "How to set up {{provider}}",
|
|
"guideDocs": "Official {{provider}} docs",
|
|
"guideStaleNote": "Provider setup screens change often, so these steps may be out of date - always confirm against the official docs."
|
|
},
|
|
"alertsHub": {
|
|
"title": "Alerts",
|
|
"description": "Define alert rules, route them to webhook channels, and review what has fired - all in one place.",
|
|
"tabRules": "Rules",
|
|
"tabChannels": "Channels",
|
|
"tabActivity": "Activity",
|
|
"rulesHint": "Conditions that trigger an alert. Evaluated server-side against the live event stream.",
|
|
"rulesEmptyHint": "Add a rule to start alerting on errors, inactivity, stuck agents, or token thresholds."
|
|
},
|
|
"jumpTo": "Jump to",
|
|
"webhookGuides": {
|
|
"slack": {
|
|
"steps": [
|
|
"Create or open a Slack app at api.slack.com/apps.",
|
|
"Turn on 'Incoming Webhooks', then click 'Add New Webhook to Workspace'.",
|
|
"Choose the channel to post to and authorize.",
|
|
"Copy the generated URL (https://hooks.slack.com/services/…) and paste it above."
|
|
]
|
|
},
|
|
"discord": {
|
|
"steps": [
|
|
"Open your server → Server Settings → Integrations → Webhooks.",
|
|
"Click 'New Webhook', pick a channel, optionally rename it.",
|
|
"Click 'Copy Webhook URL' and paste it above."
|
|
]
|
|
},
|
|
"teams": {
|
|
"steps": [
|
|
"In the target Teams channel, click ⋯ → 'Workflows'.",
|
|
"Pick the template 'Post to a channel when a webhook request is received'.",
|
|
"Finish the flow and copy the generated HTTP POST URL.",
|
|
"Paste it above. (Classic Office 365 connectors were retired in 2025 - use Workflows.)"
|
|
]
|
|
},
|
|
"google_chat": {
|
|
"steps": [
|
|
"Open the Google Chat space → space title → 'Apps & integrations'.",
|
|
"Click 'Webhooks' → 'Add webhook' and give it a name.",
|
|
"Copy the webhook URL and paste it above."
|
|
]
|
|
},
|
|
"mattermost": {
|
|
"steps": [
|
|
"Main Menu → Integrations → Incoming Webhooks (an admin must enable webhooks first).",
|
|
"Click 'Add Incoming Webhook' and choose a channel.",
|
|
"Save, then copy the webhook URL and paste it above."
|
|
]
|
|
},
|
|
"rocketchat": {
|
|
"steps": [
|
|
"Administration → Integrations → New → Incoming.",
|
|
"Enable it, pick a channel, and save.",
|
|
"Copy the 'Webhook URL' and paste it above."
|
|
]
|
|
},
|
|
"telegram": {
|
|
"steps": [
|
|
"Message @BotFather, run /newbot, and copy the bot token.",
|
|
"Add the bot to your group/channel (or just DM it).",
|
|
"Find the chat ID: send a message, open https://api.telegram.org/bot<token>/getUpdates, read result[].message.chat.id.",
|
|
"Enter the Bot token and Chat ID above - no URL needed."
|
|
]
|
|
},
|
|
"pagerduty": {
|
|
"steps": [
|
|
"Open the target Service → Integrations → 'Add integration'.",
|
|
"Choose 'Events API v2'.",
|
|
"Copy the Integration Key (the routing key).",
|
|
"Enter it as the Routing key above - the Events API URL is prefilled."
|
|
]
|
|
},
|
|
"opsgenie": {
|
|
"steps": [
|
|
"Settings → Integrations → add an 'API' integration.",
|
|
"Copy the generated API key.",
|
|
"Note your account region (US or EU).",
|
|
"Enter the API key and region above - the alerts URL is derived from the region."
|
|
]
|
|
},
|
|
"splunk_oncall": {
|
|
"steps": [
|
|
"Integrations → REST Endpoint, and enable it.",
|
|
"Copy the REST URL - it already contains your API key.",
|
|
"Replace the trailing '$routing_key' with one of your routing keys.",
|
|
"Paste the full URL above."
|
|
]
|
|
},
|
|
"zapier": {
|
|
"steps": [
|
|
"Create a Zap with the trigger 'Webhooks by Zapier' → 'Catch Hook'.",
|
|
"Copy the custom webhook URL it gives you.",
|
|
"Paste it above. The alert arrives as JSON: { event, alert }."
|
|
]
|
|
},
|
|
"make": {
|
|
"steps": [
|
|
"Add a 'Webhooks' → 'Custom webhook' module as the first step of a scenario.",
|
|
"Click 'Add', create the hook, and copy its URL.",
|
|
"Paste it above, then run once so Make learns the payload shape."
|
|
]
|
|
},
|
|
"n8n": {
|
|
"steps": [
|
|
"Add a 'Webhook' node to your workflow; set the method to POST.",
|
|
"Copy the Production URL.",
|
|
"Activate the workflow and paste the URL above (http is allowed for self-hosted)."
|
|
]
|
|
},
|
|
"pipedream": {
|
|
"steps": [
|
|
"Create a workflow with an 'HTTP / Webhook' trigger.",
|
|
"Copy the unique endpoint URL.",
|
|
"Paste it above; inspect deliveries in the Pipedream event inspector."
|
|
]
|
|
},
|
|
"generic": {
|
|
"steps": [
|
|
"Point this at any endpoint that accepts a JSON POST (https, or http for local testing).",
|
|
"Body shape: { event: 'alert.triggered', source, sent_at, alert: { … } }.",
|
|
"Optional: set a signing secret (HMAC-SHA256 over the body → X-Webhook-Signature header) and custom headers.",
|
|
"Tip: use a free inspector like webhook.site to see the exact payload."
|
|
]
|
|
}
|
|
},
|
|
"remoteSources": {
|
|
"title": "Remote Data Sources",
|
|
"description": "Collect Claude Code usage from other machines over SSH - e.g. a dev box or cloud VM you drive over SSH while running this dashboard locally. Authentication uses your own SSH setup (~/.ssh/config, keys, agent); no passwords are stored here.",
|
|
"scopeTitle": "Data scope",
|
|
"scopeDesc": "Choose which machines' data the whole dashboard shows. Changes apply immediately across every page — sessions, analytics, and cost.",
|
|
"scopeAll": "All sources",
|
|
"scopeAllDesc": "This machine plus every configured remote source, combined.",
|
|
"scopeLocal": "This machine only",
|
|
"scopeLocalDesc": "Only sessions collected locally — hides all remote-source data.",
|
|
"scopeSelected": "Selected sources",
|
|
"scopeSelectedDesc": "Pick exactly which machines to include, below.",
|
|
"scopeSelectedCount": "{{n}} of {{total}} selected",
|
|
"scopePickMachines": "Machines to include",
|
|
"thisMachine": "This machine",
|
|
"listTitle": "Configured sources",
|
|
"add": "Add source",
|
|
"addTitle": "Add a remote source",
|
|
"editTitle": "Edit source",
|
|
"fieldLabel": "Label",
|
|
"fieldHost": "SSH host",
|
|
"fieldPort": "Port (optional)",
|
|
"fieldIdentity": "Identity file (optional)",
|
|
"fieldRemoteHome": "Remote Claude home (optional)",
|
|
"fieldRemoteHomeHint": "Linux/macOS: default ~/.claude (or an absolute path like /home/you/.claude). Windows SSH + Claude in WSL: leave blank (auto-detect) or use wsl:~/.claude. Native Windows: C:/Users/you/.claude.",
|
|
"fieldEnabled": "Sync automatically in the background",
|
|
"empty": "No remote sources yet.",
|
|
"emptyHint": "Add a machine you reach over SSH to pull its Claude Code usage in.",
|
|
"paused": "Auto-sync off",
|
|
"sessionCount": "{{n}} sessions",
|
|
"sessionCountLinked": "{{n}} linked",
|
|
"sessionCountHint": "Sessions linked to this source (not every session visible when data scope is All)",
|
|
"lastSync": "Last sync: {{when}}",
|
|
"neverSynced": "Never synced",
|
|
"imported": "{{n}} imported",
|
|
"syncNew": "{{n}} new",
|
|
"syncOnRemote": "{{n}} on remote",
|
|
"test": "Test",
|
|
"syncNow": "Sync",
|
|
"syncAll": "Sync all",
|
|
"enable": "Enable",
|
|
"disable": "Disable",
|
|
"confirmDelete": "Remove this source?",
|
|
"purgeData": "Also delete the sessions imported from this source (cannot be undone)",
|
|
"deleteAndPurge": "Remove + delete data",
|
|
"removeKeep": "Remove (keep data)",
|
|
"remoteSourceBadgeTitle": "Collected from a remote machine"
|
|
},
|
|
"cursorPathsNote": "Informational: Cursor sessions count here too — Cursor happens to use the same ~/.claude paths as Claude Code (locally and on synced remotes).",
|
|
"aiRouter": {
|
|
"title": "AI Router",
|
|
"description": "Endpoints that stand in front of Claude Code and Codex — 9Router, OpenRouter, a self-hosted gateway. Save one here, then pick it when you create a workspace.",
|
|
"add": "Add profile",
|
|
"edit": "Edit",
|
|
"remove": "Remove",
|
|
"empty": "No router profile saved yet. Native runs against the vendor's own API.",
|
|
"builtinHint": "Built in — this is the vendor's own API, and it cannot be edited or removed.",
|
|
"colLabel": "Profile",
|
|
"colBaseUrl": "Endpoint",
|
|
"colModel": "Model",
|
|
"colKey": "API key",
|
|
"keySet": "Saved",
|
|
"keyMissing": "None",
|
|
"fieldLabel": "Name",
|
|
"fieldLabelHint": "What you will see in the workspace form. Free text.",
|
|
"fieldBaseUrl": "Base URL",
|
|
"fieldBaseUrlHint": "The router's OpenAI/Anthropic-compatible endpoint, e.g. http://localhost:20128/v1",
|
|
"fieldApiKey": "API key",
|
|
"fieldApiKeyHint": "Stored on this machine at 0600 and never sent back to the browser.",
|
|
"fieldApiKeyKeep": "Leave blank to keep the saved key.",
|
|
"fieldModel": "Model",
|
|
"fieldModelHint": "Used for every tier unless you override one below. Many routers accept one symbolic name.",
|
|
"perTier": "Per-tier overrides",
|
|
"perTierHint": "Leave a field blank to use the model above.",
|
|
"tier": {
|
|
"opus": "Opus",
|
|
"sonnet": "Sonnet",
|
|
"haiku": "Haiku",
|
|
"smallFast": "Small / fast",
|
|
"subagent": "Subagent"
|
|
},
|
|
"save": "Save",
|
|
"cancel": "Cancel",
|
|
"removeConfirm": "Remove the profile \"{{label}}\"? Every workspace using it is reset to the vendor's own API right away — on disk and in the dashboard.",
|
|
"loading": "Loading profiles…",
|
|
"lanesFailed": "Saved, but {{count}} workspace could not be updated and still carries the old endpoint: {{lanes}}",
|
|
"test": "Test",
|
|
"testing": "Testing…",
|
|
"testOk": "The endpoint answered — {{model}} is reachable with this key.",
|
|
"testFailed": "No answer ({{status}}): {{message}}"
|
|
},
|
|
"aiTools": {
|
|
"title": "AI Tools",
|
|
"description": "AI coding CLIs AgentHub can run in a workspace. Detected on this machine's PATH; a disabled tool is hidden from Add workspace.",
|
|
"installed": "Installed ({{count}} detected)",
|
|
"available": "Available to install ({{count}})",
|
|
"refresh": "Refresh",
|
|
"noneInstalled": "No AI tool found on PATH. Install one, then press Refresh.",
|
|
"default": "Default",
|
|
"setDefault": "Set default",
|
|
"enabled": "Enabled",
|
|
"disabled": "Disabled",
|
|
"enabledOf": "{{tool}} enabled",
|
|
"homepage": "Homepage",
|
|
"homepageOf": "{{tool}} homepage",
|
|
"install": "Install",
|
|
"update": "Update",
|
|
"updateAll": "Update all ({{count}})",
|
|
"runScript": "Download {{url}} and run it with bash",
|
|
"confirmInstall": "Install {{tool}}?",
|
|
"confirmUpdate": "Update {{tool}}?",
|
|
"confirmUpdateAll": "Update AI tools?",
|
|
"confirmBody": "AgentHub will run on this machine:",
|
|
"run": "Run",
|
|
"cancel": "Cancel",
|
|
"jobRunning": "Running…",
|
|
"jobOk": "Done",
|
|
"jobFailed": "Failed (exit {{code}})",
|
|
"showLog": "Show log",
|
|
"hideLog": "Hide log"
|
|
},
|
|
"appearance": {
|
|
"title": "Appearance",
|
|
"description": "Colour mode and theme. Saved in this browser only.",
|
|
"mode": "Mode",
|
|
"modes": {
|
|
"dark": "Dark",
|
|
"light": "Light",
|
|
"system": "System"
|
|
},
|
|
"darkThemes": "Dark themes",
|
|
"lightThemes": "Light themes",
|
|
"active": "· in use now",
|
|
"default": "Default"
|
|
},
|
|
"gitCreds": {
|
|
"title": "Git credentials",
|
|
"description": "Logins AgentHub gives git for a dashboard fetch, pull or push — one per host, shared by everyone using this AgentHub. A token is never shown again after it is saved.",
|
|
"add": "Add login",
|
|
"replace": "Replace token",
|
|
"remove": "Delete",
|
|
"removeConfirm": "Delete this git login? Dashboard fetch/pull/push to that host will ask for a login again.",
|
|
"save": "Save",
|
|
"cancel": "Cancel",
|
|
"fieldHost": "Server URL",
|
|
"fieldUser": "Username",
|
|
"fieldToken": "Password or access token",
|
|
"colHost": "Host",
|
|
"colUser": "Username",
|
|
"colSaved": "Saved",
|
|
"empty": "No git login saved. The git bar asks for one the first time a host needs it.",
|
|
"badUrl": "Enter the server as a URL, e.g. https://git.example.com"
|
|
},
|
|
"homeDir": {
|
|
"save": "Save",
|
|
"saving": "Saving...",
|
|
"current": "Current:",
|
|
"saveFailed": "Failed to save the directory",
|
|
"envOwned": "This variable is set by the environment the dashboard started in, or by the checkout's .env — either wins at every start: a value saved here lasts until the next restart."
|
|
},
|
|
"codexHome": {
|
|
"title": "CODEX_HOME",
|
|
"description": "Root directory for Codex config and session journals. The dashboard reads it, writes AI Router layers into it, and starts every codex workspace with it.",
|
|
"restartNote": "A codex workspace already running keeps the home it started with, and shows as idle, until it is restarted.",
|
|
"placeholder": "/path/to/codex-home",
|
|
"routersFailed": "Saved, but the AI Router layer could not be re-written for: {{lanes}}"
|
|
},
|
|
"codexHooks": {
|
|
"title": "Codex hooks",
|
|
"description": "Let Codex report to AgentHub as it works: each tool call in the session's timeline, \"Codex needs your permission\" on the workspace card and as a notification, and running/idle the moment a turn starts or ends. Tokens and cost come from Codex's journals either way.",
|
|
"notInstalled": "Not installed",
|
|
"untrusted": "Installed — waiting for your trust in Codex",
|
|
"trusted": "Installed and trusted",
|
|
"trustNote": "Codex runs a hook only after you trust it. The next time Codex starts it asks you to review new hooks: choose Trust all and continue (or run /hooks). Until then Codex skips them.",
|
|
"install": "Install",
|
|
"reinstall": "Reinstall",
|
|
"refresh": "Refresh",
|
|
"remove": "Remove",
|
|
"eventTrusted": "Trusted in Codex",
|
|
"eventUntrusted": "Not trusted in Codex yet",
|
|
"eventMissing": "Not installed",
|
|
"unsupported": "Codex hooks from AgentHub need a POSIX shell, so they are not available on Windows.",
|
|
"unreadable": "AgentHub cannot read {{path}}: {{error}}",
|
|
"failed": "Could not change Codex hooks: {{message}}"
|
|
},
|
|
"antigravityHooks": {
|
|
"title": "Antigravity hooks",
|
|
"description": "Let Antigravity's CLI (agy) report to AgentHub as it works: each tool call in the session's timeline, and running/idle the moment a run starts or ends. Tokens and cost come from agy's conversation files either way.",
|
|
"notInstalled": "Not installed",
|
|
"installed": "Installed",
|
|
"disabled": "Installed but switched off in hooks.json",
|
|
"note": "agy loads hooks at its next start and asks for no trust. The file is global, so the Antigravity IDE runs the hook too; AgentHub ignores what the IDE sends. agy has no hook for a permission prompt, so an Antigravity workspace cannot show \"needs your permission\".",
|
|
"install": "Install",
|
|
"reinstall": "Reinstall",
|
|
"refresh": "Refresh",
|
|
"remove": "Remove",
|
|
"eventInstalled": "Installed",
|
|
"eventMissing": "Not installed",
|
|
"unsupported": "Antigravity hooks from AgentHub need a POSIX shell, so they are not available on Windows.",
|
|
"unreadable": "AgentHub cannot read {{path}}: {{error}}",
|
|
"failed": "Could not change Antigravity hooks: {{message}}"
|
|
},
|
|
"toolTab": {
|
|
"update": "Update…",
|
|
"usage_one": "{{count}} session · ${{cost}}",
|
|
"usage_other": "{{count}} sessions · ${{cost}}",
|
|
"lanes": "Workspaces:",
|
|
"defaultModel": "Default model",
|
|
"defaultModelHint": "The model a new run in this tool's workspaces starts on. The run form can still pick another one.",
|
|
"saveDefaultModel": "Save default model",
|
|
"config": "Config files",
|
|
"configHint": "This tool's own settings files. A save is checked for valid syntax, the old text is backed up in AgentHub's data folder, and nothing is saved if the file changed since you opened it.",
|
|
"missing": "This file does not exist yet",
|
|
"save": "Save",
|
|
"close": "Close",
|
|
"saved": "Saved. Backup: {{backup}}"
|
|
},
|
|
"settingsNav": {
|
|
"label": "Settings sections",
|
|
"back": "Back to Workspace",
|
|
"group": {
|
|
"general": "General",
|
|
"agents": "Agents",
|
|
"routing": "Routing",
|
|
"git": "Git"
|
|
},
|
|
"section": {
|
|
"general": {
|
|
"title": "General",
|
|
"description": "Workspace housekeeping, data and about."
|
|
},
|
|
"appearance": {
|
|
"title": "Appearance",
|
|
"description": "Colour mode and theme. Saved in this browser only."
|
|
},
|
|
"notifications": {
|
|
"title": "Notifications",
|
|
"description": "Browser notifications, alert rules and webhooks."
|
|
},
|
|
"agents": {
|
|
"title": "AI tools",
|
|
"description": "The AI coding CLIs AgentHub can run: enable, set the default, install and update."
|
|
},
|
|
"claudeCode": {
|
|
"title": "Claude Code",
|
|
"description": "Claude Code's own configuration, and what AgentHub reads from it."
|
|
},
|
|
"codex": {
|
|
"title": "Codex",
|
|
"description": "Codex's own configuration, and what AgentHub reads from it."
|
|
},
|
|
"tool": {
|
|
"description": "{{tool}}: path, usage, default model and config files."
|
|
},
|
|
"aiRouter": {
|
|
"title": "AI Router",
|
|
"description": "Endpoints that stand in front of Claude Code and Codex."
|
|
},
|
|
"pricing": {
|
|
"title": "Pricing",
|
|
"description": "Model prices for every vendor, used to estimate cost."
|
|
},
|
|
"gitCredentials": {
|
|
"title": "Git credentials",
|
|
"description": "Logins AgentHub gives git for a dashboard fetch, pull or push."
|
|
},
|
|
"worktrees": {
|
|
"title": "Worktrees",
|
|
"description": "Which untracked git worktrees a workspace's Add folder suggests."
|
|
}
|
|
}
|
|
},
|
|
"search": {
|
|
"placeholder": "Search settings",
|
|
"noMatch": "No setting matches “{{query}}”."
|
|
},
|
|
"worktrees": {
|
|
"title": "Worktree suggestions",
|
|
"description": "When you add a folder to a workspace, the repo's worktrees that have no workspace are suggested. Saved in this browser only.",
|
|
"showUntracked": "Show untracked worktrees",
|
|
"showUntrackedDesc": "Suggest a repository's worktrees that have no workspace yet.",
|
|
"claude": "Claude Code worktrees",
|
|
"claudeDesc": "Worktrees under <repo>/.claude/worktrees/, made by Claude Code's own agents.",
|
|
"agenthub": "AgentHub-managed worktrees",
|
|
"agenthubDesc": "Worktrees AgentHub created under its workspaces root."
|
|
},
|
|
"language": {
|
|
"title": "Language",
|
|
"description": "The language of the whole dashboard, remembered in this browser.",
|
|
"label": "Interface language",
|
|
"names": {
|
|
"en": "English",
|
|
"vi": "Tiếng Việt"
|
|
}
|
|
}
|
|
}
|