feat(settings): data-safe editors, deep-linked search, Data/About/Cost pages
- EditorModal loads once per path (a parent re-render no longer reloads the file over the user's typing), refuses Save after a failed load, opens a truncated (>256 KB) file read-only, and asks before overwriting a file that changed on disk or could not be re-read. - Settings/Hooks editors unset only keys from the snapshot taken at Edit, warn when the file changed underneath, keep a renamed key's value, and refuse a new key named like a redacted one (env) or a read-only hook event, which used to replace the secret/hooks. - Project scope shows its resolved folder and is disabled inside the plugin cache. Account-profile, pricing-row and pet deletes confirm; two-click actions disarm after 3 s; unsaved drafts ask before closing. - Search indexes every Claude Code / Codex sub-tab, opens it via ?tab= and scrolls to + highlights the row; the active config tab is in the URL. - General splits into General / Data / About; Pricing moves to a Cost group with one shared load; config tabs group as Content / Extensions / Config with arrow-key roving; Promise.allSettled per tab. - Data: browser-preferences export/import (allowlisted keys), per-section reset, housekeeping dry-run first, clear-all behind a typed phrase. Server: purge days must be a whole number >= 1 (INVALID_PURGE_DAYS) and dry_run returns exactly what the real run would delete. - Alerts can be edited; webhooks/alerts/remote-source failures toast; copies go through copyText; modals get dialog roles and useDialog. - Sagi: Ctrl/Cmd+B only when shown and not typing, default spot clear of row controls, arrow keys move it, reduced motion honoured; the dead /run launch link goes to the workspace.
This commit is contained in:
@@ -20,13 +20,46 @@
|
||||
"upload": "Upload your own…",
|
||||
"import": "Import .codex-pet bundle…",
|
||||
"browse": "Find more on codex-pets.net",
|
||||
"settings": "Pet settings…"
|
||||
"settings": "Pet settings…",
|
||||
"hiddenToast": "Pet hidden. Show it again in Settings → Pet.",
|
||||
"deleteTitle": "Delete {{name}}?",
|
||||
"deleteMessage": "The pet's files are removed from this install. A featured pet can be downloaded again; an upload is gone for good.",
|
||||
"deleteConfirm": "Delete pet",
|
||||
"reset": "Reset to defaults",
|
||||
"resetDone": "Pet settings reset to defaults.",
|
||||
"hiddenNote": "The pet is hidden — size and speech bubbles apply once it is shown again.",
|
||||
"resetMessage": "Show the pet again with speech bubbles on, at 68 px, wearing Sagi. Your uploaded and downloaded pets are kept.",
|
||||
"previewCapped": "The preview is drawn at 120 px; the pet itself is {{size}} px."
|
||||
},
|
||||
"bubbles": "Speech bubbles",
|
||||
"bubblesDesc": "Let the pet comment on your sessions in a bubble",
|
||||
"sizeDesc": "{{min}}–{{max}} px; the preview is capped at 120 px",
|
||||
"chooseDesc": "Featured pets come from codex-pets.net and are downloaded into this install the first time you pick one. Your choice and size are saved in this browser.",
|
||||
"uploadHint": "An image (PNG, JPEG, GIF, WebP — no SVG) is shown still; a .codex-pet.zip (pet.json + a 1536×1872 spritesheet.webp) is animated by mood."
|
||||
"uploadHint": "An image (PNG, JPEG, GIF, WebP — no SVG) is shown still; a .codex-pet.zip (pet.json + a 1536×1872 spritesheet.webp) is animated by mood.",
|
||||
"panel": {
|
||||
"label": "Sagi companion",
|
||||
"live": "Live",
|
||||
"offline": "Offline",
|
||||
"close": "Close Sagi",
|
||||
"statLive": "live",
|
||||
"statWaiting": "waiting",
|
||||
"statErrored": "errored",
|
||||
"runClaude": "Run Claude",
|
||||
"activity": "Activity",
|
||||
"sessions": "Sessions",
|
||||
"errored": "Errored",
|
||||
"mute": "Mute",
|
||||
"unmute": "Unmute",
|
||||
"clearAlerts": "Clear alerts",
|
||||
"askPlaceholder": "Ask Sagi… (e.g. any errors?)",
|
||||
"ask": "Ask Sagi",
|
||||
"send": "Send"
|
||||
},
|
||||
"bubbleDismiss": "Dismiss",
|
||||
"open": "Open Sagi companion",
|
||||
"closeAvatar": "Close Sagi",
|
||||
"avatarTitle": "Sagi — Ctrl/⌘+B · drag or arrow keys to move · right-click for pets",
|
||||
"startFailed": "Couldn't start that session: {{error}}"
|
||||
},
|
||||
"pricing": {
|
||||
"vendor": {
|
||||
@@ -85,12 +118,17 @@
|
||||
}
|
||||
},
|
||||
"autoBadge": "Auto",
|
||||
"autoBadgeTitle": "Kept at the published rate automatically (LiteLLM's price list, checked daily). Edit it to keep your own rate."
|
||||
"autoBadgeTitle": "Kept at the published rate automatically (LiteLLM's price list, checked daily). Edit it to keep your own rate.",
|
||||
"deleteConfirmTitle": "Delete the pricing rule {{pattern}}?",
|
||||
"deleteConfirmBody": "Sessions on this model will be priced by another matching rule, or not at all. The automatic price sync will NOT add this pattern back; add it again by hand if you change your mind."
|
||||
},
|
||||
"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"
|
||||
"placeholder": "/path/to/claude-home",
|
||||
"note": "Nothing is moved or copied: AgentHub just starts reading transcripts, config and hooks from the new folder. Cursor sessions use the same ~/.claude paths, so they follow it too.",
|
||||
"confirmTitle": "Change CLAUDE_HOME?",
|
||||
"confirmBody": "AgentHub will read sessions, config, skills and hooks from the new folder from now on. Sessions under the old folder stop being imported until you switch back. Nothing is moved or deleted."
|
||||
},
|
||||
"hooks": {
|
||||
"title": "Hook Configuration",
|
||||
@@ -106,7 +144,16 @@
|
||||
"description": "Machine-wide workspace housekeeping.",
|
||||
"runHousekeeping": "Run housekeeping",
|
||||
"dryRun": "Dry run",
|
||||
"gcResult": "Reaped {{reaped}} process(es), capped {{capped}} log(s)"
|
||||
"gcResult": "Reaped {{reaped}} process(es), capped {{capped}} log(s)",
|
||||
"explain": "Cleans up after workspace sessions: stops MCP server processes that ended sessions left running, and trims workspace log files that grew too large. Nothing in your repositories is touched.",
|
||||
"preview": "Preview housekeeping",
|
||||
"gcReapLine": "stop leftover process {{pid}}",
|
||||
"gcCapLine": "trim {{path}} ({{size}})",
|
||||
"gcNothing": "Nothing to clean up — no leftover processes and no oversized logs.",
|
||||
"gcConfirmTitle": "Run housekeeping?",
|
||||
"gcConfirmBody": "This will:",
|
||||
"gcMore": "and {{count}} more",
|
||||
"gcPreviewResult": "Dry run: would stop {{reaped}} process(es) and trim {{capped}} log(s)"
|
||||
},
|
||||
"notifications": {
|
||||
"awaitingInput": "Claude needs confirmation",
|
||||
@@ -127,7 +174,7 @@
|
||||
"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",
|
||||
"testTitle": "AgentHub",
|
||||
"title": "Notifications",
|
||||
"turnComplete": "Claude finishes a turn",
|
||||
"sound": {
|
||||
@@ -140,7 +187,16 @@
|
||||
"pop": "Pop",
|
||||
"alert": "Alert",
|
||||
"forType": "Sound for this type"
|
||||
}
|
||||
},
|
||||
"scopeNote": "These notification settings are saved in this browser only. Alert rules and webhooks below are server-wide: they apply to everyone using this dashboard.",
|
||||
"insecureOrigin": "This page is served from {{origin}}, which is not a secure origin. Browsers only show notifications on HTTPS or localhost — open the dashboard through one of those to get them.",
|
||||
"unsupported": "This browser does not support notifications.",
|
||||
"deniedHelp": "Notifications are blocked for this site. To allow them again, open the site settings (the icon left of the address bar), set Notifications to Allow, then reload this page.",
|
||||
"pushFailed": "Notifications are on, but push could not be set up ({{message}}). They will still show while this tab is open.",
|
||||
"reset": "Reset to defaults",
|
||||
"resetTitle": "Reset notification settings?",
|
||||
"resetBody": "Every notification type and sound goes back to its default. Whether notifications are on stays as it is.",
|
||||
"resetDone": "Notification settings reset."
|
||||
},
|
||||
"import": {
|
||||
"title": "Import History",
|
||||
@@ -230,7 +286,10 @@
|
||||
"runCleanup": "Run Cleanup",
|
||||
"nothingToClean": "Nothing to clean up",
|
||||
"abandonedResult": " sessions abandoned",
|
||||
"purgedResult": " sessions purged ({{events}} events, {{agents}} agents)"
|
||||
"purgedResult": " sessions purged ({{events}} events, {{agents}} agents)",
|
||||
"wholeNumber": "Enter a whole number, 1 or more (or leave blank to skip).",
|
||||
"cleanupConfirmTitle": "Run session cleanup?",
|
||||
"cleanupConfirmBody": "This marks {{abandoned}} stale session(s) abandoned and permanently deletes {{sessions}} old session(s) with {{events}} event(s) and {{agents}} agent(s). Deleted sessions cannot be restored — export first if you may need them."
|
||||
},
|
||||
"danger": {
|
||||
"title": "Danger Zone",
|
||||
@@ -238,7 +297,11 @@
|
||||
"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"
|
||||
"clearedResult": "Cleared {{count}} rows",
|
||||
"dialogTitle": "Clear all data?",
|
||||
"exportFirst": "Export your data first.",
|
||||
"typeToConfirm": "Type “{{phrase}}” to confirm:",
|
||||
"phrase": "clear all data"
|
||||
},
|
||||
"about": {
|
||||
"title": "About",
|
||||
@@ -322,7 +385,11 @@
|
||||
"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."
|
||||
"guideStaleNote": "Provider setup screens change often, so these steps may be out of date - always confirm against the official docs.",
|
||||
"loadFailed": "Could not load webhook targets: {{error}}",
|
||||
"toggleFailed": "Could not change the webhook: {{error}}",
|
||||
"deleteFailed": "Could not delete the webhook: {{error}}",
|
||||
"pickRule": "Tick at least one rule, or choose all rules."
|
||||
},
|
||||
"alertsHub": {
|
||||
"title": "Alerts",
|
||||
@@ -493,7 +560,8 @@
|
||||
"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"
|
||||
"remoteSourceBadgeTitle": "Collected from a remote machine",
|
||||
"fieldLabelPlaceholder": "Dev box"
|
||||
},
|
||||
"cursorPathsNote": "Informational: Cursor sessions count here too — Cursor happens to use the same ~/.claude paths as Claude Code (locally and on synced remotes).",
|
||||
"aiRouter": {
|
||||
@@ -579,7 +647,11 @@
|
||||
"darkThemes": "Dark themes",
|
||||
"lightThemes": "Light themes",
|
||||
"active": "· in use now",
|
||||
"default": "Default"
|
||||
"default": "Default",
|
||||
"reset": "Reset to defaults",
|
||||
"resetTitle": "Reset appearance?",
|
||||
"resetBody": "Mode goes back to Dark and both modes to their default theme.",
|
||||
"resetDone": "Appearance reset."
|
||||
},
|
||||
"gitCreds": {
|
||||
"title": "Git credentials",
|
||||
@@ -597,7 +669,9 @@
|
||||
"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"
|
||||
"badUrl": "Enter the server as a URL, e.g. https://git.example.com",
|
||||
"saved": "Login saved for {{host}}.",
|
||||
"loading": "Loading…"
|
||||
},
|
||||
"homeDir": {
|
||||
"save": "Save",
|
||||
@@ -660,7 +734,11 @@
|
||||
"missing": "This file does not exist yet",
|
||||
"save": "Save",
|
||||
"close": "Close",
|
||||
"saved": "Saved. Backup: {{backup}}"
|
||||
"saved": "Saved. Backup: {{backup}}",
|
||||
"defaultModelSaved": "Default model saved.",
|
||||
"staleBody": "This file changed on disk since you opened it, so nothing was saved. Copy your version if you need it, then reload.",
|
||||
"copyMine": "Copy my version",
|
||||
"reloadDiscard": "Reload (discard mine)"
|
||||
},
|
||||
"settingsNav": {
|
||||
"label": "Settings sections",
|
||||
@@ -669,12 +747,13 @@
|
||||
"general": "General",
|
||||
"agents": "Agents",
|
||||
"routing": "Routing",
|
||||
"git": "Git"
|
||||
"git": "Git",
|
||||
"cost": "Cost"
|
||||
},
|
||||
"section": {
|
||||
"general": {
|
||||
"title": "General",
|
||||
"description": "Workspace housekeeping, data and about."
|
||||
"description": "The dashboard's display language."
|
||||
},
|
||||
"appearance": {
|
||||
"title": "Appearance",
|
||||
@@ -718,12 +797,23 @@
|
||||
"worktrees": {
|
||||
"title": "Worktrees",
|
||||
"description": "Which untracked git worktrees a workspace's Add folder suggests."
|
||||
},
|
||||
"data": {
|
||||
"title": "Data",
|
||||
"description": "Cost and database overview, import, remote sources, export, cleanup and the danger zone."
|
||||
},
|
||||
"about": {
|
||||
"title": "About",
|
||||
"description": "Server version, uptime and runtime."
|
||||
}
|
||||
}
|
||||
},
|
||||
"backPrevious": "Back",
|
||||
"unknownSection": "There is no “{{section}}” settings page — showing General instead."
|
||||
},
|
||||
"search": {
|
||||
"placeholder": "Search settings",
|
||||
"noMatch": "No setting matches “{{query}}”."
|
||||
"noMatch": "No setting matches “{{query}}”.",
|
||||
"results": "Search results"
|
||||
},
|
||||
"worktrees": {
|
||||
"title": "Worktree suggestions",
|
||||
@@ -751,5 +841,15 @@
|
||||
"copyPath": "Copy path",
|
||||
"enable": "Enable",
|
||||
"disable": "Disable"
|
||||
},
|
||||
"prefsBackup": {
|
||||
"title": "This browser's preferences",
|
||||
"description": "Theme, language, notification settings, pet, sidebar and workspace layout are kept in this browser. Save them to a file to move them to another browser, or restore them from one.",
|
||||
"export": "Export preferences",
|
||||
"import": "Import preferences…",
|
||||
"importTitle": "Import preferences?",
|
||||
"importBody": "The file's preferences replace this browser's, then the page reloads.",
|
||||
"imported": "Imported {{count}} preference(s). Reloading…",
|
||||
"badFile": "That file is not an AgentHub preferences file."
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user