From 055aabc989a0bda5f76d41f4e6a4ecb3a82355c8 Mon Sep 17 00:00:00 2001 From: CodeWhale Bot Date: Wed, 2 Sep 2026 13:32:31 -0700 Subject: [PATCH 1/3] copy(errors): warmer, shorter failure and status receipts Rewrite $\sim0 error/status strings in en.json (send failures, permissions, sessions, automation, compaction, provider, telemetry prefs, voice, clipboard) and lowercase the product name to codewhale in user-visible inline errors. Keys, placeholders, and parsed punctuation unchanged. Tests: 167 targeted + 704 config/runtime_api pass; 65 locale goldens pass; cargo fmt clean; check-tui-product-vocabulary.sh clean. --- crates/tui/locales/en.json | 158 +++++++++--------- crates/tui/src/cloud_dispatch.rs | 10 +- .../tui/src/commands/groups/config/config.rs | 4 +- .../src/commands/groups/config/permissions.rs | 4 +- crates/tui/src/commands/groups/core/copy.rs | 9 +- crates/tui/src/config.rs | 42 ++--- crates/tui/src/config_ui.rs | 2 +- crates/tui/src/continual_harness.rs | 2 +- crates/tui/src/dispatch_runner.rs | 10 +- crates/tui/src/lib.rs | 18 +- crates/tui/src/palette/user_theme.rs | 2 +- crates/tui/src/remote_control.rs | 74 ++++---- crates/tui/src/runtime_api.rs | 4 +- crates/tui/src/settings.rs | 2 +- crates/tui/src/skill_state.rs | 2 +- crates/tui/src/tools/subagent/mod.rs | 2 +- crates/tui/src/tui/ui/apply.rs | 2 +- crates/tui/src/tui/ui/event_loop.rs | 2 +- crates/tui/src/tui/ui/handlers.rs | 2 +- crates/tui/src/tui/ui/tests.rs | 20 +-- crates/tui/src/tui/views/fleet_list.rs | 2 +- .../src/tui/widgets/pending_input_preview.rs | 4 +- 22 files changed, 187 insertions(+), 190 deletions(-) diff --git a/crates/tui/locales/en.json b/crates/tui/locales/en.json index f456091566..b71f5f472d 100644 --- a/crates/tui/locales/en.json +++ b/crates/tui/locales/en.json @@ -92,11 +92,11 @@ "ComposerHintQueue": "↵ send after this turn", "ComposerHintQueueWithCount": "↵ send after this turn ({count} waiting)", "ComposerHintOfflineQueue": "↵ save for later", - "ComposerHintOfflineConnect": "↵ save for later · /provider connects", + "ComposerHintOfflineConnect": "↵ save for later · /provider to connect", "ComposerHintSendNow": "↵ send now", "ComposerHintSendIntoTurn": "↵ send into this turn", "PendingSendingIntoTurnPrefix": " ↳ Sending into this turn: ", - "PendingCouldNotSendIntoTurnPrefix": " ↳ Could not send into this turn: ", + "PendingCouldNotSendIntoTurnPrefix": " ↳ Held for next turn: ", "PendingEditingFollowUpPrefix": " ↳ Editing follow-up: ", "PendingQueuedOnePrefix": "Queued #1: ", "PendingQueuedManyPrefix": "Queued {count} · next: ", @@ -106,16 +106,16 @@ "PendingQueuedFollowUpPrefix": " ↳ Queued follow-up #{number}: ", "PendingInputsHeader": "Pending inputs", "PendingContextHeader": "Context for next send", - "ToastQueuedFollowUp": "Queued. Sends after this turn.", - "ToastQueuedFollowUpCount": "Queued ({count} waiting). Sends after this turn.", + "ToastQueuedFollowUp": "Queued — sends after this turn.", + "ToastQueuedFollowUpCount": "Queued ({count} waiting) — sends after this turn.", "ToastQueuedOffline": "Saved for later. Connect a provider to send.", "ToastSentIntoTurn": "Sent into this turn.", - "ToastCouldNotSendIntoTurn": "Could not send into this turn; kept in queue.", + "ToastCouldNotSendIntoTurn": "Couldn't send into this turn; kept in the queue.", "ToastHookBlockedFollowUp": "A hook blocked the follow-up; it stayed in the queue.", "ToastOfflineQueuedCount": "Offline: {count} saved for later.", - "ComposerDispatchFailedRestored": "Message not sent ({error}); restored to composer.", - "DispatchFailedQueued": "Dispatch failed ({error}); kept {count} queued follow-up(s).", - "DispatchFailedInitial": "Initial prompt could not be sent: {error}", + "ComposerDispatchFailedRestored": "Not sent ({error}) — draft restored to the composer.", + "DispatchFailedQueued": "Send failed ({error}); kept {count} queued follow-up(s).", + "DispatchFailedInitial": "Could not send your first message: {error}", "HistorySearchPlaceholder": "Search prompt history...", "HistorySearchTitle": "History Search", "HistoryHintMove": "Up/Down move", @@ -135,11 +135,11 @@ "TelemetryNoticeReceiptDisabled": "Anonymous usage counting is off. You will not be asked again.", "TelemetryNoticeReceiptEnabledUnsaved": "Anonymous usage counts are on for this session. Codewhale could not save this notice, so it will appear again. Change this in /settings; schema: docs/TELEMETRY.md", "TelemetryNoticeReceiptDisabledUnsaved": "Anonymous usage counting is off for this session. Codewhale could not save the choice, so it will ask again next launch.", - "TelemetryPreferenceEnabledNextLaunch": "Anonymous usage counts will be on next launch. Conversations and code are never collected.", - "TelemetryPreferenceDisabled": "Anonymous usage counts are off. Local telemetry state was erased.", - "TelemetryPreferenceDisabledWithWarning": "Anonymous usage counts are off, but part of the cleanup needs attention: {detail}", - "TelemetryPreferenceDisabledForSession": "Anonymous usage counts are off for this session, but the preference was not saved and may return next launch: {detail}", - "TelemetryPreferenceSaveFailed": "The telemetry preference could not be changed safely: {detail}", + "TelemetryPreferenceEnabledNextLaunch": "Anonymous counts return next launch. Conversations and code stay private.", + "TelemetryPreferenceDisabled": "Anonymous counts are off; local telemetry state was erased.", + "TelemetryPreferenceDisabledWithWarning": "Anonymous usage counts are off, but one cleanup step needs attention: {detail}", + "TelemetryPreferenceDisabledForSession": "Counting is off for this session. The choice couldn't be saved, so it returns next launch: {detail}", + "TelemetryPreferenceSaveFailed": "Could not save the telemetry choice: {detail}", "StatusPickerTitle": " Status line ", "StatusPickerInstruction": "Pick the chips you want in the footer:", "StatusPickerActionToggle": "toggle ", @@ -217,7 +217,7 @@ "ConfigScopeSession": "SESSION", "ConfigScopeSaved": "SAVED", "ConfigCommandSource": "{value} (source: {source})", - "ConfigCommandInvalidValue": "Invalid {key} '{value}'. Use: {choices}.", + "ConfigCommandInvalidValue": "Can't use '{value}' for {key}. Try: {choices}.", "ConfigSearchUpdated": "search.provider = {value} ({scope}; subsequent web_search calls use the effective provider after environment overrides)", "ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; ghost-text hints apply after subsequent turns)", "ConfigNotificationsSetHint": "Set with /config notifications [--save].", @@ -331,7 +331,7 @@ "ModelPickerAutoLocalHint": "per turn · local heuristic · no router request", "ModelPickerAutoLastRoute": "last {provider} · {model}", "AutoRouteSelectedToast": "Auto: {provider} / {model} via {source} · Ctrl+O: route details", - "CloudCodeSystemPromptUnsupported": "Antigravity cloud-code cannot safely send this turn because this wire does not support system instructions yet. Nothing was sent; choose another provider.", + "CloudCodeSystemPromptUnsupported": "Antigravity cloud-code can't carry system instructions yet — nothing was sent. Choose another provider.", "HelpTitle": "Help", "HelpFilterPlaceholder": "Type to filter", "HelpFilterPrefix": "Filter: ", @@ -363,7 +363,7 @@ "CmdConfigDescription": "Inspect and change settings (raw keys as advanced detail)", "CmdPermissionsDescription": "List and safely remove permission rules", "PermissionsListHeader": "Permission rules\nSource: active user permissions.toml\nPath: {path}\nFile status: {file_state}\nRule count: {count}", - "PermissionsNoRules": "No permission rules configured.", + "PermissionsNoRules": "No permission rules yet.", "PermissionsFileMissing": "missing", "PermissionsFileEmpty": "empty", "PermissionsFilePresent": "present", @@ -375,12 +375,12 @@ "PermissionsScopeGlobal": "global", "PermissionsScopeRepo": "repo `{workspace}`", "PermissionsAppliesHere": "active in this workspace", - "PermissionsInactiveHere": "not active in this workspace", - "PermissionsRemovePreview": "Review removal of rule #{index}:\n{rule}\n\nRun `{command}` to confirm. This command expires if permissions.toml changes.", - "PermissionsRemoved": "Removed permission rule #{index}: {action} {tool}.", + "PermissionsInactiveHere": "inactive in this workspace", + "PermissionsRemovePreview": "Remove rule #{index}?\n{rule}\n\nRun `{command}` to confirm. It expires if permissions.toml changes.", + "PermissionsRemoved": "Removed rule #{index}: {action} {tool}.", "PermissionsUsage": "Usage: /permissions [list|remove [--confirm ]]", - "PermissionsRuleNotFound": "Permission rule #{index} was not found; run `/permissions list` again.", - "PermissionsOperationFailed": "Permission rule operation failed: {error}", + "PermissionsRuleNotFound": "No permission rule #{index}; run `/permissions list` again.", + "PermissionsOperationFailed": "Could not update the permission rule: {error}", "CmdConstitutionDescription": "Manage standing constitution law and previews", "CmdContextDescription": "Open context inspector or source-map report", "CmdCostDescription": "Show session cost breakdown", @@ -389,13 +389,13 @@ "CmdExitDescription": "Exit the application", "CmdExportDescription": "Copy a safe conversation export, or write it to an explicit file", "CmdCopyDescription": "Copy the last completed assistant response to the clipboard", - "CmdCopyNoOutput": "No completed assistant response is available to copy", - "CmdCopySuccess": "Accepted the last completed assistant response for clipboard delivery; a recovery copy is at {path}", - "CmdCopySuccessNoBackup": "The last completed assistant response was accepted for clipboard delivery, but no recovery file could be written. Use `/export file ` to choose a destination", - "CmdCopyQueued": "Queued the last completed assistant response for the terminal-client clipboard; a recovery copy is at {path}", - "CmdCopyQueuedNoBackup": "Queued the last completed assistant response for the terminal-client clipboard; no recovery file could be written. Use `/export file ` to choose a destination", - "CmdCopyFailed": "Clipboard copy failed: {error}. The response was saved to {path}", - "CmdCopyFailedNoBackup": "Clipboard copy failed: {error}. No recovery file could be written; use `/export file ` to choose a destination", + "CmdCopyNoOutput": "Nothing to copy yet — no completed response.", + "CmdCopySuccess": "Copied the last response; a backup is at {path}.", + "CmdCopySuccessNoBackup": "Copied the last response, but no backup could be written. Use `/export file ` for a destination.", + "CmdCopyQueued": "Queued the last response for the clipboard; a backup is at {path}.", + "CmdCopyQueuedNoBackup": "Queued the last response for the clipboard, but no backup could be written. Use `/export file ` for a destination.", + "CmdCopyFailed": "Couldn't copy ({error}); the response is saved at {path}.", + "CmdCopyFailedNoBackup": "Couldn't copy ({error}), and no backup could be written. Use `/export file ` instead.", "CmdFeedbackDescription": "Generate a GitHub feedback URL", "CmdHfDescription": "Inspect Hugging Face MCP setup and concepts", "CmdHelpDescription": "Understand concepts, commands, and keybindings", @@ -513,9 +513,9 @@ "CmdRemoteEnvDescription": "Open new hosted Work from a GitHub or CNB branch tip", "CmdRemoteEnvOverview": "Hosted Work starts a new environment from the branch tip available at GitHub or CNB.\n\nIt does not move this local folder or include unpushed commits, dirty or ignored files, secrets, or session state.\n\nUse {command} to open the hosted Work launcher.", "CmdRemoteEnvOpening": "Opening hosted Work for {repo} on branch {branch}.\n\nThis starts a new environment from the branch tip available at the Git host configured as {origin}. Local-only state is not included.\n\nIf the browser does not open, use:\n{url}", - "CmdRemoteEnvUnavailable": "Codewhale could not resolve both a supported GitHub or CNB origin and a checked-out branch for this folder. Check out a branch and configure {origin} with an HTTPS or SSH URL, then try {command} again. Nothing was created or allocated.", - "CmdRemoteEnvSourceCustodyPolicy": "Codewhale does not upload, migrate, or sync local source into hosted Work. Use {command} to start from the branch tip available at GitHub or CNB. Unpushed commits, dirty or ignored files, secrets, and session state stay local.", - "CmdRemoteEnvBrowserLabel": "Codewhale hosted Work", + "CmdRemoteEnvUnavailable": "codewhale could not resolve both a supported GitHub or CNB origin and a checked-out branch for this folder. Check out a branch and configure {origin} with an HTTPS or SSH URL, then try {command} again. Nothing was created or allocated.", + "CmdRemoteEnvSourceCustodyPolicy": "codewhale does not upload, migrate, or sync local source into hosted Work. Use {command} to start from the branch tip available at GitHub or CNB. Unpushed commits, dirty or ignored files, secrets, and session state stay local.", + "CmdRemoteEnvBrowserLabel": "codewhale hosted Work", "CmdRenameDescription": "Rename the current session", "CmdTitleDescription": "Set a tab/window title shown as [title] … in the terminal title", "CmdRestoreDescription": "Roll back the workspace to a prior pre/post-turn snapshot. With no arg, lists recent snapshots.", @@ -549,7 +549,7 @@ "CmdStructcopyPrepareFailed": "Could not prepare the selected {kind}: {error}", "CmdStructcopyClipboardQueued": "Structural copy ({kind}, {bytes} bytes) was queued for the terminal-client clipboard via tmux/OSC 52; delivery depends on terminal support and is not confirmed", "CmdStructcopyClipboardAccepted": "Structural copy ({kind}, {bytes} bytes) was handed to the clipboard; if no native clipboard was reachable, a terminal write was queued instead", - "CmdStructcopyClipboardFailed": "Clipboard copy failed: {error}. Nothing was written; run again with `stdout` for an explicit text view", + "CmdStructcopyClipboardFailed": "Couldn't reach the clipboard ({error}); nothing was written. Re-run with `stdout` to see the text.", "CmdStructcopyReceiptTooLarge": "Structural-copy receipt metadata exceeds the {bytes}-byte output cap; refusing to emit it", "CmdFleetDescription": "Inspect and set up fleet members and orchestration state", "CmdLaneDescription": "Inspect and control durable Lanes (running Workflows)", @@ -565,9 +565,9 @@ "CmdTranslateDescription": "Toggle output translation to the current system language on/off", "CmdTranslateOff": "Output translation disabled (original model output shown)", "CmdTranslateOn": "Output translation enabled: model responses will be shown in your system language", - "TranslationInProgress": "Translating assistant output...", - "TranslationComplete": "Translation complete", - "TranslationFailed": "Translation failed", + "TranslationInProgress": "Translating...", + "TranslationComplete": "Translated.", + "TranslationFailed": "Couldn't translate.", "CmdTrustDescription": "Manage workspace trust and the per-path allowlist", "CmdWorkspaceDescription": "Show or switch the current workspace", "CmdUndoDescription": "Remove last message pair", @@ -673,7 +673,7 @@ "SettingsTitle": "Settings:", "SettingsConfigFile": "Config file:", "ClearConversation": "Conversation cleared", - "ClearConversationBusy": "Nothing cleared (Work state or runtime work busy; wait, then try /clear again)", + "ClearConversationBusy": "Still busy — nothing cleared. Try /clear again in a moment.", "ModelChanged": "Model changed: {old} →, {new}", "LinksProjectTitle": "Codewhale & community:", "LinksDocumentation": "Documentation:", @@ -1040,13 +1040,13 @@ "ApprovalBlockTitle": "approval", "ApprovalControlsHint": " · Pg↑/↓ review · {details} details · Esc abort", "ApprovalTruncationHint": " … truncated · press {details} for full details", - "ApprovalFullAccessPolicyBlocked": "Blocked {tool}: Full Access cannot bypass this policy", + "ApprovalFullAccessPolicyBlocked": "Blocked {tool}: even Full Access must honor this policy", "AutoReviewQuestionSkipped": "Auto-Review skipped a user question and continued autonomously", "ApprovalChooseHint": "Choose: ", "ApprovalChooseAction": "Enter selected option, or press y/a/d directly", "ApprovalIntentLabel": "Intent: ", "ApprovalMoreLines": " … (+{count} lines)", - "ApprovalAutoDeniedSession": "Auto-denied {tool}: a matching request was denied earlier during this Codewhale run. Restart Codewhale to reconsider it.", + "ApprovalAutoDeniedSession": "Auto-denied {tool}: you denied a matching request earlier in this run. Restart codewhale to reconsider it.", "ElevationTitleSandboxDenied": " ⚠, Sandbox Denied ", "ElevationTitleRequired": " Sandbox Elevation Required ", "ElevationFieldTool": " Tool: ", @@ -1065,13 +1065,13 @@ "ElevationOptionWriteDesc": "Retry this tool call with additional writable filesystem scope", "ElevationOptionFullAccessDesc": "Retry without sandbox limits; grants unrestricted filesystem and network access", "ElevationOptionAbortDesc": "Cancel this tool execution", - "ContextAutoCompacting": "Context automatically compacting…", + "ContextAutoCompacting": "Auto-compacting context…", "ContextManualCompacting": "Compacting context…", - "ContextCompactionQueued": "Context compaction queued; it will run after the active turn.", - "ContextCompactionAlreadyRunning": "Context compaction is already in progress.", - "ContextCompactionQueueFull": "Context compaction could not be queued because the engine is busy; try again after the turn completes.", - "ContextCompactionQueueClosed": "Context compaction is unavailable because the engine is no longer running.", - "ContextCompactionRouteInvalid": "Cannot compact because the active provider route is invalid: {error}", + "ContextCompactionQueued": "Compaction queued — runs after this turn.", + "ContextCompactionAlreadyRunning": "Compaction is already running.", + "ContextCompactionQueueFull": "Compaction has to wait — the engine is busy. Try again after this turn.", + "ContextCompactionQueueClosed": "Compaction is unavailable — the engine stopped.", + "ContextCompactionRouteInvalid": "Can't compact — the active provider route is invalid: {error}", "CtxInspTitle": "Context inspector", "CtxInspSessionContext": "Session Context", "CtxInspSystemPrompt": "System Prompt Structure", @@ -1134,17 +1134,17 @@ "CmdVoiceDescription": "Toggle voice input: record speech and transcribe into the composer", "CmdVoiceSendDescription": "Toggle voice auto-send: submit when the transcript ends with \"send it\"", "CmdVoiceControlDescription": "Toggle voice control: AI-assisted dictation aware of the composer text", - "VoiceEnabled": "Voice input enabled. Speak to record.", - "VoiceDisabled": "Voice input disabled.", - "VoiceSendEnabled": "Voice auto-send enabled.", - "VoiceSendDisabled": "Voice auto-send disabled.", - "VoiceControlEnabled": "Voice control enabled.", - "VoiceControlDisabled": "Voice control disabled.", - "VoiceErrNoAuth": "Voice: no API key configured for the active provider", - "VoiceErrNoRecorder": "Voice: no recording tool found. Install sox, arecord, or rec.", - "VoiceErrNetwork": "Voice: transcription request failed", - "VoiceErrEmptySend": "Voice: nothing to send", - "VoiceErrTooShort": "Voice: no speech detected, recording too short", + "VoiceEnabled": "Voice on — speak to record.", + "VoiceDisabled": "Voice off.", + "VoiceSendEnabled": "Voice auto-send on.", + "VoiceSendDisabled": "Voice auto-send off.", + "VoiceControlEnabled": "Voice control on.", + "VoiceControlDisabled": "Voice control off.", + "VoiceErrNoAuth": "Voice needs an API key for the active provider.", + "VoiceErrNoRecorder": "Voice found no recorder. Install sox, arecord, or rec.", + "VoiceErrNetwork": "Voice transcription failed — try again.", + "VoiceErrEmptySend": "Voice: nothing recorded to send.", + "VoiceErrTooShort": "Voice heard nothing — the recording was too short.", "VoiceRecording": "🎙 Recording... speak now", "VoiceProcessing": "🎙 Transcribing...", "VoiceTranscribed": "🎙 Transcribed", @@ -1260,7 +1260,7 @@ "LaunchSavedSessionSingular": "1 saved session", "LaunchSavedSessionsPlural": "{count} saved sessions", "LaunchCreatingWorktree": "Creating worktree…", - "LaunchWorktreeFailed": "Worktree failed: {error}", + "LaunchWorktreeFailed": "Could not create the worktree: {error}", "LaunchNoSavedSessions": "No saved sessions for this workspace.", "LaunchComposerHint": "Enter send · Shift+Enter new line · Esc back", "LaunchNoModelConnected": "no model connected", @@ -1326,17 +1326,17 @@ "SessionsSortName": "name", "SessionsSortSize": "size", "SessionsSearchPrompt": "Search: type to filter, Enter to apply", - "SessionsDeleteFailed": "Delete failed: {error}", - "SessionsDeleted": "Deleted session {id}", + "SessionsDeleteFailed": "Could not delete: {error}", + "SessionsDeleted": "Deleted {id}", "SessionsNoSelection": "No session selected", "SessionsTitleLength": "Title must be 1–100 characters", "SessionsOpenFailed": "Could not open sessions: {error}", - "SessionsLoadFailed": "Could not load session: {error}", - "SessionsRenameFailed": "Rename failed: {error}", + "SessionsLoadFailed": "Could not load the session: {error}", + "SessionsRenameFailed": "Could not rename: {error}", "SessionsRenamed": "Renamed to \"{title}\"", "SessionsNoResults": "No sessions found.", - "SessionsDirectoryFailed": "Failed to open sessions directory.", - "SessionsPreviewFailed": "Failed to load session preview.", + "SessionsDirectoryFailed": "Could not open the sessions folder.", + "SessionsPreviewFailed": "Could not load the session preview.", "SessionsDeleteCancelled": "Delete cancelled", "SessionsRenameCancelled": "Rename cancelled", "SessionsShowingRange": "Showing {start}-{end} / {total}", @@ -1456,10 +1456,10 @@ "ProviderExternalOwnerOnly": "Owner: {owner}", "ProviderExternalPinnedPathChanged": "Warning: ambient {owner} credential path changed; consent stays pinned to the granted path.", "ProviderExternalRevokeConfirmTitle": " Revoke external credential access? ", - "ProviderExternalGrantedToast": "Read-only {owner} access granted for {provider}. No refresh, identity/discovery requests, or external-file writes; normal provider requests may use the token.", - "ProviderExternalSaveFailedToast": "External credential consent was not saved: {error}", - "ProviderExternalRevokedToast": "External credential access revoked for {provider}", - "ProviderExternalRevokeFailedToast": "External credential access was not revoked: {error}", + "ProviderExternalGrantedToast": "Read-only {owner} access granted for {provider} — token use only, no refresh, discovery, or writes.", + "ProviderExternalSaveFailedToast": "Couldn't save the credential consent: {error}", + "ProviderExternalRevokedToast": "Revoked external access for {provider}.", + "ProviderExternalRevokeFailedToast": "Couldn't revoke external access: {error}", "ThemeSurfaceTitle": "theme · live preview", "ThemeTreatmentDeepseaUnavailable": "Treatment Deepsea unavailable — Terminal owns the background", "ThemeTreatmentFlatActive": "Treatment Flat — active", @@ -1521,7 +1521,7 @@ "FleetDestUnavailable": "Not available: {reason}", "FleetDestReasonNoProjectConfig": "project profiles are disabled for this session (--no-project-config)", "FleetDestReasonWorkspaceMissing": "the workspace folder {path} does not exist or is not a directory", - "FleetDestReasonHomeUnavailable": "your Codewhale home could not be resolved ({error})", + "FleetDestReasonHomeUnavailable": "your codewhale home could not be resolved ({error})", "FleetDestWillReplace": "Will replace the existing file {path}", "FleetDestOverridesProject": "This project already has a '{id}' profile, which takes precedence here; this Personal profile applies in other projects.", "FleetDestOverridesPersonal": "Takes precedence over your Personal '{id}' profile inside this project.", @@ -1624,7 +1624,7 @@ "ThinkingControlledByAutoRouting": "Thinking is controlled by automatic model routing; choose a fixed model first.", "SavedAsStartupDefault": "saved as startup default", "ModeAlreadyActiveSavedAsDefault": "Already in {mode} mode — saved as startup default.", - "StartupDefaultNotSaved": "{setting} was not saved: {error}", + "StartupDefaultNotSaved": "{setting} couldn't be saved: {error}", "StartupDefaultSubjectMode": "startup mode", "StartupDefaultSubjectThinking": "thinking level", "StartupDefaultSubjectModel": "model", @@ -1636,9 +1636,9 @@ "SessionsRailUnavailable": "Sessions unavailable: {error}", "SessionsActionArchive": "archive", "SessionsActionShowArchived": "archived", - "SessionsArchived": "Archived session {id}", - "SessionsRestored": "Restored session {id}", - "SessionsArchiveFailed": "Archive failed: {error}", + "SessionsArchived": "Archived {id}", + "SessionsRestored": "Restored {id}", + "SessionsArchiveFailed": "Could not archive: {error}", "SessionsShowingArchived": "Showing archived sessions", "SessionsHidingArchived": "Hiding archived sessions", "SessionsArchivedCompact": "archived", @@ -1647,10 +1647,10 @@ "CmdTurnInspectDescription": "Open the whole-turn inspector", "CmdAutomationDescription": "Manage durable scheduled automations", "AutomationUsage": "Usage: /automation [list|show |pause |resume |delete [--confirm ]|run ]", - "AutomationManagerUnavailable": "Automation manager is not available in this session.", + "AutomationManagerUnavailable": "Automations aren't available this session.", "AutomationListFailed": "Could not list automations: {error}", "AutomationActionFailed": "Could not {action} automation {id}: {error}", - "AutomationEmpty": "No scheduled automations. Use the `automation` tool to create one.", + "AutomationEmpty": "No automations yet. The `automation` tool creates one.", "AutomationListHeading": "Scheduled automations", "AutomationNoun": "Automation", "AutomationStatusLabel": "status", @@ -1693,8 +1693,8 @@ "AutomationReceiptDeleted": "deleted", "AutomationRunLabel": "run", "AutomationDeletedRunsDetail": "recorded runs deleted: {run_count}", - "AutomationDeletePreview": "Deletion is not armed. Nothing was deleted.\nAutomation: {id} ({name})\nRecorded runs: {run_count}\nTo delete the definition and run history, run:\n{command}", - "AutomationDeleteConfirmationStale": "Deletion confirmation no longer matches automation {id}; nothing was deleted. Review the current state with {command}.", + "AutomationDeletePreview": "Not armed — nothing was deleted.\nAutomation: {id} ({name})\nRecorded runs: {run_count}\nTo delete it and its history, run:\n{command}", + "AutomationDeleteConfirmationStale": "That confirmation expired for {id}; nothing was deleted. Check {command} and try again.", "WhaleStateResting": "Resting", "WhaleStateThinking": "Thinking", "WhaleStateWorking": "Working", @@ -1784,7 +1784,7 @@ "AutoReviewReceiptGuardianDenied": "Auto-Review denied '{tool}' ({risk} risk, model guardian): {reason}", "AutoReviewReceiptGuardianUnavailable": "Auto-Review could not review '{tool}' ({reason}); denied, fail closed", "AutoReviewReceiptDeterministicBlocked": "Auto-Review blocked '{tool}' (deterministic policy): {reason}", - "AutoReviewReceiptHeld": "Auto-Review held '{tool}' without pausing; denied (needs a person — switch to Ask)", + "AutoReviewReceiptHeld": "Auto-Review held '{tool}' (needs a person); denied — switch to Ask", "FooterHintEscInterrupt": "Esc to interrupt", "PostureHintEnterAgain": "{enter} again to send now · {steer} steers", "PermissionsPostureHeader": "Access now: {posture}", @@ -1853,9 +1853,9 @@ "ConfigHintProviderTemplates": "P in /provider; C-t tests /models without treating 2xx as model-ready", "ProviderConnectionChecked": "Connection checked (/models returned 2xx). Model availability is not checked.", "ProviderConnectionCheckedPickModel": "Connection checked (/models returned 2xx). Pick a default model; model availability is not checked.", - "ProviderTestConnectionNeedKey": "No API key saved for {provider}. Enter a key first, then press T to test the connection.", - "ProviderTestConnectionFailed": "{provider} connection check failed: {error}", - "ProviderTestConnectionNoEndpoint": "{provider} has no /models endpoint; reachability was not probed.", + "ProviderTestConnectionNeedKey": "No API key saved for {provider}. Add one first, then press T to test.", + "ProviderTestConnectionFailed": "Could not reach {provider}: {error}", + "ProviderTestConnectionNoEndpoint": "{provider} exposes no /models endpoint; reachability unprobed.", "ProviderTemplateOpened": "Provider template '{id}' opened. Enter an API key only.", "ProviderTemplateUnknown": "Unknown provider template '{id}'.", "ProviderTemplateOpenedEnvOnly": "Built-in template '{id}' opened. Enter the API key env var name, then save. Do not paste a raw key.", diff --git a/crates/tui/src/cloud_dispatch.rs b/crates/tui/src/cloud_dispatch.rs index 73df46731d..37ac2f17e4 100644 --- a/crates/tui/src/cloud_dispatch.rs +++ b/crates/tui/src/cloud_dispatch.rs @@ -1070,7 +1070,7 @@ pub fn format_job(job: &CloudJob) -> String { ]; if let Some(minutes) = runtime_minutes(job) { lines.push(format!( - "Runtime: {minutes}m (Codewhale bookkeeping, not a bill)" + "Runtime: {minutes}m (codewhale bookkeeping, not a bill)" )); } if let Some(summary) = job.agent_summary.as_deref() { @@ -1093,7 +1093,7 @@ pub fn format_status( credentials: &CredentialState, recent: &[CloudJob], ) -> String { - let mut lines = vec!["Codewhale cloud dispatch".to_string()]; + let mut lines = vec!["codewhale cloud dispatch".to_string()]; match credentials { CredentialState::Missing => { if membership_signed_in() { @@ -1103,7 +1103,7 @@ pub fn format_status( ); } else { lines.push( - "Cloud agents are included with your Codewhale membership. Sign in with `codewhale login` to enable `/dispatch`; cloud dispatch fails closed until then (no sandbox, no push, no PR)." + "Cloud agents are included with your codewhale membership. Sign in with `codewhale login` to enable `/dispatch`; cloud dispatch fails closed until then (no sandbox, no push, no PR)." .to_string(), ); } @@ -1822,7 +1822,7 @@ pub fn missing_credentials_message() -> String { if membership_signed_in() { "Cloud agents are not available for this account yet; cloud dispatch fails closed (no sandbox, no push, no PR).".to_string() } else { - "Cloud agents are included with your Codewhale membership. Sign in with `codewhale login` to enable `/dispatch`; cloud dispatch fails closed until then (no sandbox, no push, no PR).".to_string() + "Cloud agents are included with your codewhale membership. Sign in with `codewhale login` to enable `/dispatch`; cloud dispatch fails closed until then (no sandbox, no push, no PR).".to_string() } } @@ -2059,7 +2059,7 @@ fn forge_host(forge: Forge) -> &'static str { fn proposal_note(plan: &DispatchPlan) -> String { format!( - "Proposed Codewhale cloud-agent offload to {} ({}) raising branch {}.", + "Proposed codewhale cloud-agent offload to {} ({}) raising branch {}.", plan.remote.forge.as_str(), plan.remote.name, plan.branch diff --git a/crates/tui/src/commands/groups/config/config.rs b/crates/tui/src/commands/groups/config/config.rs index aabf1caad6..0e1adf0f1e 100644 --- a/crates/tui/src/commands/groups/config/config.rs +++ b/crates/tui/src/commands/groups/config/config.rs @@ -4633,7 +4633,7 @@ completion_sound = "bell" assert!(search.is_error); let search_msg = search.message.unwrap(); assert!( - search_msg.contains("Invalid search.provider"), + search_msg.contains("Can't use 'not-a-backend' for search.provider"), "{search_msg}" ); assert!(search_msg.contains("firecrawl"), "{search_msg}"); @@ -4642,7 +4642,7 @@ completion_sound = "bell" assert!(notifications.is_error); let notifications_msg = notifications.message.unwrap(); assert!( - notifications_msg.contains("Invalid notifications.method"), + notifications_msg.contains("Can't use 'semaphore' for notifications.method"), "{notifications_msg}" ); assert!(notifications_msg.contains("osc9"), "{notifications_msg}"); diff --git a/crates/tui/src/commands/groups/config/permissions.rs b/crates/tui/src/commands/groups/config/permissions.rs index e3e011cffc..d283fda79c 100644 --- a/crates/tui/src/commands/groups/config/permissions.rs +++ b/crates/tui/src/commands/groups/config/permissions.rs @@ -316,7 +316,7 @@ workspace = {other:?} assert!(message.contains("active in this workspace")); assert!(message.contains("#2 | ask | edit_file")); assert!(message.contains("exact normalized path `src/lib.rs`")); - assert!(message.contains("not active in this workspace")); + assert!(message.contains("inactive in this workspace")); } #[test] @@ -349,7 +349,7 @@ workspace = {other:?} let malformed = permissions_command(&app, Some("list")); let malformed_message = malformed.message.expect("malformed message"); assert!(malformed.is_error); - assert!(malformed_message.contains("Permission rule operation failed")); + assert!(malformed_message.contains("Could not update the permission rule")); assert!(malformed_message.contains(&codewhale_config::quote_os_path( &displayed_permissions_path ))); diff --git a/crates/tui/src/commands/groups/core/copy.rs b/crates/tui/src/commands/groups/core/copy.rs index e505283f22..b7cf1ebc9c 100644 --- a/crates/tui/src/commands/groups/core/copy.rs +++ b/crates/tui/src/commands/groups/core/copy.rs @@ -138,7 +138,7 @@ mod tests { let result = execute_copy(&mut app); let expected = format!( - "Accepted the last completed assistant response for clipboard delivery; a recovery copy is at {}", + "Copied the last response; a backup is at {}.", tmp.path().join("exports").join("last-copy.md").display() ); assert_eq!(result.message.as_deref(), Some(expected.as_str())); @@ -169,7 +169,7 @@ mod tests { assert_eq!( result.message.as_deref(), - Some("No completed assistant response is available to copy") + Some("Nothing to copy yet — no completed response.") ); } @@ -353,10 +353,7 @@ mod tests { assert!(!result.is_error); let message = result.message.as_deref().unwrap_or_default(); - assert!( - message.contains("no recovery file could be written"), - "{message}" - ); + assert!(message.contains("no backup could be written"), "{message}"); assert!(message.contains("/export file "), "{message}"); } diff --git a/crates/tui/src/config.rs b/crates/tui/src/config.rs index c9f5e2236e..b401356697 100644 --- a/crates/tui/src/config.rs +++ b/crates/tui/src/config.rs @@ -5192,7 +5192,7 @@ impl Config { return self.resolve_provider_identity(name); } return Err(format!( - "legacy session records only the generic `custom` provider kind, but the live config does not select exactly one valid named custom route (selected '{}', valid named routes: {}). Restore the original single `[providers.]` route or repair the saved provider identity; Codewhale will not guess or fall back", + "legacy session records only the generic `custom` provider kind, but the live config does not select exactly one valid named custom route (selected '{}', valid named routes: {}). Restore the original single `[providers.]` route or repair the saved provider identity; codewhale will not guess or fall back", if selected.is_empty() { "" } else { @@ -5211,12 +5211,12 @@ impl Config { .and_then(|providers| providers.custom_provider_config(exact_key)) .ok_or_else(|| { format!( - "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}]` is missing from the live config. Restore that exact table and retry; Codewhale will not fall back" + "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}]` is missing from the live config. Restore that exact table and retry; codewhale will not fall back" ) })?; if !entry.is_openai_compatible_custom() { return Err(format!( - "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}]` must set `kind = \"openai-compatible\"`. Fix the live config and retry; Codewhale will not fall back" + "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}]` must set `kind = \"openai-compatible\"`. Fix the live config and retry; codewhale will not fall back" )); } let base_url = entry @@ -5226,17 +5226,17 @@ impl Config { .filter(|base_url| !base_url.is_empty()) .ok_or_else(|| { format!( - "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}]` has no `base_url`. Fix the live config and retry; Codewhale will not fall back" + "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}]` has no `base_url`. Fix the live config and retry; codewhale will not fall back" ) })?; let parsed = reqwest::Url::parse(base_url).map_err(|err| { format!( - "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}].base_url` is invalid: {err}. Fix the live config and retry; Codewhale will not fall back" + "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}].base_url` is invalid: {err}. Fix the live config and retry; codewhale will not fall back" ) })?; if !matches!(parsed.scheme(), "http" | "https") || parsed.host_str().is_none() { return Err(format!( - "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}].base_url` must be an http(s) URL with a host. Fix the live config and retry; Codewhale will not fall back" + "saved session requires custom provider '{exact_key}', but `[providers.{exact_key}].base_url` must be an http(s) URL with a host. Fix the live config and retry; codewhale will not fall back" )); } @@ -5280,7 +5280,7 @@ impl Config { let id = persisted.trim(); if id.is_empty() { return Err( - "persisted provider route has an empty exact provider id; Codewhale will not guess or fall back" + "persisted provider route has an empty exact provider id; codewhale will not guess or fall back" .to_string(), ); } @@ -5291,14 +5291,14 @@ impl Config { .is_some(); if id.eq_ignore_ascii_case(ApiProvider::Custom.as_str()) && !has_exact_custom_table { return Err(format!( - "persisted provider route requires exact custom provider '{id}', but `[providers.{id}]` is missing from the live config. Restore that exact table and retry; Codewhale will not fall back" + "persisted provider route requires exact custom provider '{id}', but `[providers.{id}]` is missing from the live config. Restore that exact table and retry; codewhale will not fall back" )); } let identity = self.resolve_provider_identity(id)?; if identity.provider == ApiProvider::Custom && identity.persisted_id() != Some(id) { return Err(format!( - "persisted provider route requires exact custom provider '{id}', but the live config only provides the legacy root-level custom route. Restore `[providers.{id}]` and retry; Codewhale will not fall back" + "persisted provider route requires exact custom provider '{id}', but the live config only provides the legacy root-level custom route. Restore `[providers.{id}]` and retry; codewhale will not fall back" )); } Ok(identity) @@ -5332,7 +5332,7 @@ impl Config { return id.map_or_else( || { Err( - "persisted provider route has neither a provider kind nor an exact provider id; Codewhale will not guess or fall back" + "persisted provider route has neither a provider kind nor an exact provider id; codewhale will not guess or fall back" .to_string(), ) }, @@ -5348,7 +5348,7 @@ impl Config { && id != kind { return Err(format!( - "persisted provider route has legacy identity '{kind}' but exact provider id '{id}'; repair the mismatched fields because Codewhale will not guess or fall back" + "persisted provider route has legacy identity '{kind}' but exact provider id '{id}'; repair the mismatched fields because codewhale will not guess or fall back" )); } return match id { @@ -5370,7 +5370,7 @@ impl Config { let identity = self.resolve_exact_provider_identity(id)?; if identity.provider != ApiProvider::Custom { return Err(format!( - "persisted provider route declares generic kind 'custom' but exact provider id '{id}' resolves as built-in '{}'; use the matching built-in kind or restore `[providers.{id}]`. Codewhale will not guess or fall back", + "persisted provider route declares generic kind 'custom' but exact provider id '{id}' resolves as built-in '{}'; use the matching built-in kind or restore `[providers.{id}]`. codewhale will not guess or fall back", identity.provider.as_str() )); } @@ -5395,7 +5395,7 @@ impl Config { && ApiProvider::parse(id) == Some(ApiProvider::Ollama)) { return Err(format!( - "persisted provider route declares built-in kind '{}' but exact provider id '{id}' names a different route; repair the mismatched fields because Codewhale will not guess or fall back", + "persisted provider route declares built-in kind '{}' but exact provider id '{id}' names a different route; repair the mismatched fields because codewhale will not guess or fall back", provider.as_str() )); } @@ -5412,7 +5412,7 @@ impl Config { .is_some() { return Err(format!( - "persisted provider route requires built-in '{}', but an exact `[providers.{}]` custom route shadows the same selector. Rename the custom route or update the saved provider kind/id pair; Codewhale will not guess or fall back", + "persisted provider route requires built-in '{}', but an exact `[providers.{}]` custom route shadows the same selector. Rename the custom route or update the saved provider kind/id pair; codewhale will not guess or fall back", provider.as_str(), provider.as_str() )); @@ -5453,7 +5453,7 @@ impl Config { fn validate_legacy_literal_custom_route(&self) -> std::result::Result<(), String> { if self.has_literal_custom_provider_table() { return Err( - "legacy `provider = \"custom\"` is ambiguous because `[providers.custom]` is also present. Move the route to one named `[providers.]` table and update the saved provider identity; Codewhale will not guess or fall back" + "legacy `provider = \"custom\"` is ambiguous because `[providers.custom]` is also present. Move the route to one named `[providers.]` table and update the saved provider identity; codewhale will not guess or fall back" .to_string(), ); } @@ -5465,7 +5465,7 @@ impl Config { let selected = self.provider.as_deref().map(str::trim).unwrap_or_default(); if !self.selects_literal_custom_provider() { return Err(format!( - "legacy session records only the generic `custom` provider kind, but the live config selects '{}'. Only an unchanged legacy config with `provider = \"custom\"` and root-level `base_url`/`default_text_model` can load this session; Codewhale will not guess or fall back", + "legacy session records only the generic `custom` provider kind, but the live config selects '{}'. Only an unchanged legacy config with `provider = \"custom\"` and root-level `base_url`/`default_text_model` can load this session; codewhale will not guess or fall back", if selected.is_empty() { "" } else { @@ -5480,17 +5480,17 @@ impl Config { .map(str::trim) .filter(|base_url| !base_url.is_empty()) .ok_or_else(|| { - "legacy `provider = \"custom\"` requires a non-empty root-level `base_url` to load a saved session; Codewhale will not use the custom-provider placeholder or fall back" + "legacy `provider = \"custom\"` requires a non-empty root-level `base_url` to load a saved session; codewhale will not use the custom-provider placeholder or fall back" .to_string() })?; let parsed = reqwest::Url::parse(base_url).map_err(|err| { format!( - "legacy `provider = \"custom\"` has an invalid root-level `base_url`: {err}. Fix the live config and retry; Codewhale will not fall back" + "legacy `provider = \"custom\"` has an invalid root-level `base_url`: {err}. Fix the live config and retry; codewhale will not fall back" ) })?; if !matches!(parsed.scheme(), "http" | "https") || parsed.host_str().is_none() { return Err( - "legacy `provider = \"custom\"` requires a root-level `base_url` with an http(s) scheme and host; Codewhale will not fall back" + "legacy `provider = \"custom\"` requires a root-level `base_url` with an http(s) scheme and host; codewhale will not fall back" .to_string(), ); } @@ -5501,12 +5501,12 @@ impl Config { .map(str::trim) .filter(|model| !model.is_empty()) .ok_or_else(|| { - "legacy `provider = \"custom\"` requires a non-empty root-level `default_text_model` to load a saved session; Codewhale will not guess or fall back" + "legacy `provider = \"custom\"` requires a non-empty root-level `default_text_model` to load a saved session; codewhale will not guess or fall back" .to_string() })?; if model.eq_ignore_ascii_case("auto") || normalize_custom_model_id(model).is_none() { return Err( - "legacy `provider = \"custom\"` requires one explicit, valid root-level `default_text_model` (not `auto`) to load a saved session; Codewhale will not guess or fall back" + "legacy `provider = \"custom\"` requires one explicit, valid root-level `default_text_model` (not `auto`) to load a saved session; codewhale will not guess or fall back" .to_string(), ); } diff --git a/crates/tui/src/config_ui.rs b/crates/tui/src/config_ui.rs index b95c045ed0..210731ffd3 100644 --- a/crates/tui/src/config_ui.rs +++ b/crates/tui/src/config_ui.rs @@ -87,7 +87,7 @@ pub struct SettingsSection { pub theme: UiThemeValue, #[schemars( title = "Custom theme name", - description = "Theme slug from the fixed Codewhale themes directory; used only when theme is custom." + description = "Theme slug from the fixed codewhale themes directory; used only when theme is custom." )] #[serde(default, skip_serializing_if = "Option::is_none")] pub custom_theme_name: Option, diff --git a/crates/tui/src/continual_harness.rs b/crates/tui/src/continual_harness.rs index b24df6aa23..4a78601c13 100644 --- a/crates/tui/src/continual_harness.rs +++ b/crates/tui/src/continual_harness.rs @@ -257,7 +257,7 @@ fn load_state(path: &Path) -> Result { } if state.schema_version > SCHEMA_VERSION { bail!( - "continual harness state {} uses newer schema {}; this Codewhale supports schema {}", + "continual harness state {} uses newer schema {}; this codewhale supports schema {}", path.display(), state.schema_version, SCHEMA_VERSION diff --git a/crates/tui/src/dispatch_runner.rs b/crates/tui/src/dispatch_runner.rs index 546334c775..07b1cb5ede 100644 --- a/crates/tui/src/dispatch_runner.rs +++ b/crates/tui/src/dispatch_runner.rs @@ -206,7 +206,7 @@ fn drive( job.sandbox_pending = false; job.sandbox_id = Some(receipt.sandbox_id.clone()); job.note = format!( - "Sandbox {} created; the Codewhale cloud agent turn is running.", + "Sandbox {} created; the codewhale cloud agent turn is running.", receipt.sandbox_id ); if !store.save_unless_canceled(job)? { @@ -394,7 +394,7 @@ pub fn compose_pr_body_for_head(job: &CloudJob, patch: &PatchReceipt, head_sha: patch.summary.trim().to_string() }; let body = format!( - "Automated change by a Codewhale cloud agent.\n\n\ + "Automated change by a codewhale cloud agent.\n\n\ ## What the agent did\n{summary}\n\n\ ## Task\n{}\n\n\ ## Receipts\n\ @@ -623,7 +623,7 @@ fn open_pr_gitee( body: &str, ) -> Result { let token = read_service_token("gitee").ok_or_else(|| { - anyhow!("a Gitee access token is not configured in the Codewhale service slot; the branch was pushed but no pull request was opened") + anyhow!("a Gitee access token is not configured in the codewhale service slot; the branch was pushed but no pull request was opened") })?; let url = validate_outbound_origin(&gitee_pr_url(slug))?; let response = reqwest::blocking::Client::builder() @@ -666,7 +666,7 @@ fn open_pr_cnb( body: &str, ) -> Result { let token = read_service_token("cnb").ok_or_else(|| { - anyhow!("a CNB access token is not configured in the Codewhale service slot; the branch was pushed but no pull request was opened") + anyhow!("a CNB access token is not configured in the codewhale service slot; the branch was pushed but no pull request was opened") })?; let url = validate_outbound_origin(&cnb_pr_url(slug))?; let response = reqwest::blocking::Client::builder() @@ -1358,7 +1358,7 @@ mod tests { let title = compose_pr_title(&job, &patch); assert_eq!(title, "codewhale cloud: Fix the flaky dispatch test"); let body = compose_pr_body(&job, &patch); - assert!(body.contains("Codewhale cloud agent")); + assert!(body.contains("codewhale cloud agent")); assert!(body.contains("What the agent did")); assert!(body.contains("Fix the flaky dispatch test")); assert!(body.contains("open a PR that fixes the flake")); diff --git a/crates/tui/src/lib.rs b/crates/tui/src/lib.rs index 0057cd59b5..b31337f4d5 100644 --- a/crates/tui/src/lib.rs +++ b/crates/tui/src/lib.rs @@ -205,7 +205,7 @@ fn install_rustls_crypto_provider() { bin_name = "codewhale-tui", author, version = env!("CODEWHALE_BUILD_VERSION"), - about = "Codewhale terminal coding agent", + about = "codewhale terminal coding agent", long_about = "Terminal-native TUI and CLI for open-source and open-weight coding models.\n\nRun 'codewhale' to start.\n\nProvider routes include DeepSeek, Arcee, Hugging Face, OpenRouter, Xiaomi MiMo, local vLLM/SGLang/Ollama, and more." )] struct Cli { @@ -971,7 +971,7 @@ fn resolve_exec_resume_route( .map_err(anyhow::Error::msg) .with_context(|| { format!( - "saved session provider '{}' is unavailable; Codewhale will not fall back", + "saved session provider '{}' is unavailable; codewhale will not fall back", saved_provider_identity ) })?; @@ -1459,13 +1459,13 @@ enum McpCommand { }, /// Validate MCP config and required servers Validate, - /// Register this Codewhale binary as a local MCP stdio server. + /// Register this codewhale binary as a local MCP stdio server. /// /// This adds a config entry that runs `codewhale serve --mcp` (stdio protocol). /// For the HTTP/SSE runtime API, use `codewhale serve --http` directly instead. #[command( name = "add-self", - long_about = "Register this Codewhale binary as a local MCP stdio server.\n\nAdds a config entry to ~/.codewhale/mcp.json that launches `codewhale serve --mcp`\nvia the stdio transport. Other Codewhale sessions (or any MCP client) can then\ndiscover and call tools exposed by this server.\n\nUse `codewhale serve --http` instead if you need the HTTP/SSE runtime API." + long_about = "Register this codewhale binary as a local MCP stdio server.\n\nAdds a config entry to ~/.codewhale/mcp.json that launches `codewhale serve --mcp`\nvia the stdio transport. Other codewhale sessions (or any MCP client) can then\ndiscover and call tools exposed by this server.\n\nUse `codewhale serve --http` instead if you need the HTTP/SSE runtime API." )] AddSelf { /// Server name in mcp.json (default: "codewhale") @@ -1806,7 +1806,7 @@ fn run_with_args(args: Vec) -> Result<()> { .name("codewhale-main".to_string()) .stack_size(CODEWHALE_MAIN_STACK_BYTES) .spawn(move || run_async_main(cli, command, plugin_discovery, plugin_registry)) - .context("Failed to start the Codewhale runtime thread")?; + .context("Failed to start the codewhale runtime thread")?; match runtime_thread.join() { Ok(result) => result, Err(payload) => { @@ -1815,7 +1815,7 @@ fn run_with_args(args: Vec) -> Result<()> { .map(|value| (*value).to_string()) .or_else(|| payload.downcast_ref::().cloned()) .unwrap_or_else(|| "unknown panic payload".to_string()); - Err(anyhow!("Codewhale runtime thread panicked: {message}")) + Err(anyhow!("codewhale runtime thread panicked: {message}")) } } } @@ -1880,7 +1880,7 @@ pub(crate) fn build_runtime(command: Option<&Commands>) -> Result { eprintln!( - "Codewhale ignored non-credential settings in {}: {}. Use config.toml, CLI flags, or the launching shell for control settings.", + "codewhale ignored non-credential settings in {}: {}. Use config.toml, CLI flags, or the launching shell for control settings.", report.path.display(), display_env_key_set(&report.ignored) ); diff --git a/crates/tui/src/palette/user_theme.rs b/crates/tui/src/palette/user_theme.rs index 0745aae6bd..7623ae41d6 100644 --- a/crates/tui/src/palette/user_theme.rs +++ b/crates/tui/src/palette/user_theme.rs @@ -170,7 +170,7 @@ pub fn resolve_user_theme(value: &str) -> Result, Str pub fn user_themes_dir() -> Result { codewhale_config::codewhale_home() .map(|home| home.join("themes")) - .map_err(|error| format!("failed to resolve Codewhale themes directory: {error}")) + .map_err(|error| format!("failed to resolve codewhale themes directory: {error}")) } fn reject_symlink_directory(path: &Path) -> Result<(), String> { diff --git a/crates/tui/src/remote_control.rs b/crates/tui/src/remote_control.rs index 111b82a9b8..cfcf1db8cc 100644 --- a/crates/tui/src/remote_control.rs +++ b/crates/tui/src/remote_control.rs @@ -3776,13 +3776,13 @@ async fn enroll_device( .and_then(Value::as_u64) .filter(|value| (1..=30).contains(value)) .ok_or_else(|| { - "Codewhale returned an invalid device authorization interval.".to_string() + "codewhale returned an invalid device authorization interval.".to_string() })?; let expires_in = value .get("expiresIn") .and_then(Value::as_u64) .filter(|value| (60..=1800).contains(value)) - .ok_or_else(|| "Codewhale returned an invalid device authorization expiry.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid device authorization expiry.".to_string())?; validate_authorization_url(&verification_uri, &user_code)?; let _ = event_tx.send(RemoteEvent::Notice(format!( "Authorize this terminal at {verification_uri} (code {user_code})." @@ -3803,7 +3803,7 @@ async fn enroll_device( .json(&json!({ "deviceCode": device_code })) .send() .await - .map_err(|_| "Remote-control authorization could not reach Codewhale.".to_string())?; + .map_err(|_| "Remote-control authorization could not reach codewhale.".to_string())?; if response.status() == StatusCode::ACCEPTED { continue; } @@ -3824,12 +3824,12 @@ fn enrollment_from_exchange( start: &RemoteStart, ) -> Result { if value.get("status").and_then(Value::as_str) != Some("approved") { - return Err("Codewhale returned an invalid runner credential.".to_string()); + return Err("codewhale returned an invalid runner credential.".to_string()); } let record = value .get("enrollment") .filter(|value| value.is_object()) - .ok_or_else(|| "Codewhale returned an invalid runner credential.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid runner credential.".to_string())?; let enrollment_id = opaque_field(record, "id")?; let account_ref = opaque_field(record, "userId")?; let returned_device = opaque_field(record, "deviceId")?; @@ -3858,7 +3858,7 @@ fn enrollment_from_exchange( .and_then(|grant| grant.get("grantId")) .and_then(Value::as_str) .filter(|value| valid_opaque_ref(value)) - .ok_or_else(|| "Codewhale returned no grant for this session.".to_string())? + .ok_or_else(|| "codewhale returned no grant for this session.".to_string())? .to_string(); Ok(LiveEnrollment { persisted: PersistedEnrollment { @@ -3894,7 +3894,7 @@ async fn refresh_enrollment( })) .send() .await - .map_err(|_| "Remote-control credential refresh could not reach Codewhale.".to_string())?; + .map_err(|_| "Remote-control credential refresh could not reach codewhale.".to_string())?; if matches!( response.status(), StatusCode::UNAUTHORIZED | StatusCode::FORBIDDEN @@ -3908,7 +3908,7 @@ async fn refresh_enrollment( let record = value .get("enrollment") .filter(|value| value.is_object()) - .ok_or_else(|| "Codewhale returned an invalid refreshed credential.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid refreshed credential.".to_string())?; if record.get("id").and_then(Value::as_str) != Some(persisted.runner_enrollment_id.as_str()) || record.get("userId").and_then(Value::as_str) != Some(persisted.account_ref.as_str()) || record.get("deviceId").and_then(Value::as_str) != Some(persisted.device_id.as_str()) @@ -3918,7 +3918,7 @@ async fn refresh_enrollment( != Some(persisted.runtime_commit.as_str()) || !exact_capabilities(record.get("capabilities")) { - return Err("Codewhale returned a mismatched refreshed credential.".to_string()); + return Err("codewhale returned a mismatched refreshed credential.".to_string()); } Ok(LiveEnrollment { persisted, @@ -4048,17 +4048,17 @@ fn parse_runner_connection( .filter(|record| { record.len() == 2 && record.contains_key("runner") && record.contains_key("attachment") }) - .ok_or_else(|| "Codewhale returned an invalid runner attachment response.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid runner attachment response.".to_string())?; let runner = response .get("runner") .and_then(Value::as_object) - .ok_or_else(|| "Codewhale returned an invalid runner lease.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid runner lease.".to_string())?; let runner_id = runner .get("id") .and_then(Value::as_str) .filter(|value| valid_opaque_ref(value)) .map(ToString::to_string) - .ok_or_else(|| "Codewhale returned an invalid runner lease.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid runner lease.".to_string())?; let runner_binding_matches = runner.get("userId").and_then(Value::as_str) == Some(enrollment.persisted.account_ref.as_str()) && runner.get("deviceId").and_then(Value::as_str) @@ -4073,7 +4073,7 @@ fn parse_runner_connection( && runner.get("active").and_then(Value::as_bool) == Some(true) && exact_capabilities(runner.get("capabilities")); if !runner_binding_matches { - return Err("Codewhale returned a runner lease for a different session.".to_string()); + return Err("codewhale returned a runner lease for a different session.".to_string()); } let attachment = response @@ -4088,35 +4088,35 @@ fn parse_runner_connection( && record.contains_key("runtimeChatRelayProtocol") && record.contains_key("runtimeChatRelayChallenge") }) - .ok_or_else(|| "Codewhale returned an invalid session attachment.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid session attachment.".to_string())?; let run_id = attachment .get("runId") .and_then(Value::as_str) .filter(|value| valid_opaque_ref(value)) .map(ToString::to_string) - .ok_or_else(|| "Codewhale returned an invalid attached run.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid attached run.".to_string())?; let workspace_id = attachment .get("workspaceId") .and_then(Value::as_str) .filter(|value| valid_opaque_ref(value)) .map(ToString::to_string) - .ok_or_else(|| "Codewhale returned an invalid attached workspace.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid attached workspace.".to_string())?; let runtime_cursor = attachment .get("runtimeCursor") .and_then(Value::as_u64) .filter(|value| *value <= JS_MAX_SAFE_INTEGER) - .ok_or_else(|| "Codewhale returned an invalid runtime event cursor.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid runtime event cursor.".to_string())?; let snapshot_present = attachment .get("snapshotPresent") .and_then(Value::as_bool) - .ok_or_else(|| "Codewhale returned an invalid snapshot receipt.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid snapshot receipt.".to_string())?; let runtime_chat_relay_protocol = attachment .get("runtimeChatRelayProtocol") .and_then(Value::as_str) .filter(|value| *value == RUNTIME_CHAT_RELAY_PROTOCOL) .map(ToString::to_string) .ok_or_else(|| { - "Codewhale returned an unsupported Runtime Chat relay protocol.".to_string() + "codewhale returned an unsupported Runtime Chat relay protocol.".to_string() })?; let runtime_chat_relay_challenge = attachment .get("runtimeChatRelayChallenge") @@ -4128,7 +4128,7 @@ fn parse_runner_connection( .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-')) }) .map(ToString::to_string) - .ok_or_else(|| "Codewhale returned an invalid Runtime Chat relay challenge.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid Runtime Chat relay challenge.".to_string())?; let links = parse_remote_links(runner, &run_id); @@ -4255,14 +4255,14 @@ async fn list_runs( .get("runs") .and_then(Value::as_array) .filter(|runs| runs.len() <= MAX_RUNS) - .ok_or_else(|| "Codewhale returned an invalid runner run list.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid runner run list.".to_string())?; runs.iter() .map(|run| { run.get("id") .and_then(Value::as_str) .filter(|value| valid_opaque_ref(value)) .map(ToString::to_string) - .ok_or_else(|| "Codewhale returned an invalid runner run.".to_string()) + .ok_or_else(|| "codewhale returned an invalid runner run.".to_string()) }) .collect() } @@ -4297,7 +4297,7 @@ async fn list_commands( .get("commands") .and_then(Value::as_array) .filter(|commands| commands.len() <= MAX_COMMANDS) - .ok_or_else(|| "Codewhale returned an invalid command list.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid command list.".to_string())?; commands .iter() .map(|item| { @@ -4305,12 +4305,12 @@ async fn list_commands( .get("seq") .and_then(Value::as_u64) .filter(|value| *value > since) - .ok_or_else(|| "Codewhale returned an invalid command sequence.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid command sequence.".to_string())?; let command = item .get("command") .filter(|value| value.is_object()) .cloned() - .ok_or_else(|| "Codewhale returned an invalid typed command.".to_string())?; + .ok_or_else(|| "codewhale returned an invalid typed command.".to_string())?; Ok(ListedCommand { seq, command, @@ -4585,7 +4585,7 @@ async fn public_request( .json(&body) .send() .await - .map_err(|_| "Remote control could not reach Codewhale.".to_string())?; + .map_err(|_| "Remote control could not reach codewhale.".to_string())?; if !response.status().is_success() { let status = response.status(); let excerpt = rejection_excerpt(response).await; @@ -4646,17 +4646,17 @@ async fn read_bounded_json(response: reqwest::Response) -> Result .content_length() .is_some_and(|length| length > MAX_RESPONSE_BYTES as u64) { - return Err("Codewhale returned an oversized remote-control response.".to_string()); + return Err("codewhale returned an oversized remote-control response.".to_string()); } let bytes = response .bytes() .await - .map_err(|_| "Codewhale returned an unreadable response.".to_string())?; + .map_err(|_| "codewhale returned an unreadable response.".to_string())?; if bytes.len() > MAX_RESPONSE_BYTES { - return Err("Codewhale returned an oversized remote-control response.".to_string()); + return Err("codewhale returned an oversized remote-control response.".to_string()); } serde_json::from_slice(&bytes) - .map_err(|_| "Codewhale returned an invalid remote-control response.".to_string()) + .map_err(|_| "codewhale returned an invalid remote-control response.".to_string()) } fn runner_control_plane_base() -> Result { @@ -4860,10 +4860,10 @@ fn access_token(value: &Value) -> Result { .filter(|value| { (64..=8192).contains(&value.len()) && !value.chars().any(char::is_whitespace) }) - .ok_or_else(|| "Codewhale returned an invalid runner access token.".to_string())? + .ok_or_else(|| "codewhale returned an invalid runner access token.".to_string())? .to_string(); if jwt_expiry(&token).is_none_or(|expiry| expiry <= epoch_seconds()) { - return Err("Codewhale returned an expired runner access token.".to_string()); + return Err("codewhale returned an expired runner access token.".to_string()); } Ok(token) } @@ -4879,7 +4879,7 @@ fn exact_capabilities(value: Option<&Value>) -> bool { fn validate_authorization_url(value: &str, user_code: &str) -> Result<(), String> { let url = Url::parse(value) - .map_err(|_| "Codewhale returned an invalid authorization URL.".to_string())?; + .map_err(|_| "codewhale returned an invalid authorization URL.".to_string())?; let pairs = url.query_pairs().collect::>(); if url.scheme() != "https" || url.host_str() != Some("app.codewhale.net") @@ -4892,7 +4892,7 @@ fn validate_authorization_url(value: &str, user_code: &str) -> Result<(), String || pairs[0].0 != "user_code" || pairs[0].1 != user_code { - return Err("Codewhale returned an invalid authorization URL.".to_string()); + return Err("codewhale returned an invalid authorization URL.".to_string()); } Ok(()) } @@ -4904,7 +4904,7 @@ fn string_field(value: &Value, field: &str) -> Result { .map(str::trim) .filter(|value| !value.is_empty() && value.len() <= 2048) .map(ToString::to_string) - .ok_or_else(|| format!("Codewhale returned an invalid {field}.")) + .ok_or_else(|| format!("codewhale returned an invalid {field}.")) } fn secret_field(value: &Value, field: &str) -> Result { @@ -4913,7 +4913,7 @@ fn secret_field(value: &Value, field: &str) -> Result { .and_then(Value::as_str) .filter(|value| valid_secret(value)) .map(ToString::to_string) - .ok_or_else(|| format!("Codewhale returned an invalid {field}.")) + .ok_or_else(|| format!("codewhale returned an invalid {field}.")) } fn opaque_field(value: &Value, field: &str) -> Result { @@ -4922,7 +4922,7 @@ fn opaque_field(value: &Value, field: &str) -> Result { .and_then(Value::as_str) .filter(|value| valid_opaque_ref(value)) .map(ToString::to_string) - .ok_or_else(|| format!("Codewhale returned an invalid {field}.")) + .ok_or_else(|| format!("codewhale returned an invalid {field}.")) } fn valid_opaque_ref(value: &str) -> bool { diff --git a/crates/tui/src/runtime_api.rs b/crates/tui/src/runtime_api.rs index 9136602c7d..e4773d7354 100644 --- a/crates/tui/src/runtime_api.rs +++ b/crates/tui/src/runtime_api.rs @@ -840,7 +840,7 @@ pub async fn run_http_server( bail!("Port must be > 0"); } if options.web && options.host != "127.0.0.1" { - bail!("Codewhale web is loopback-only and must bind to 127.0.0.1"); + bail!("codewhale web is loopback-only and must bind to 127.0.0.1"); } if options.web && options.insecure_no_auth { bail!("Codewhale web requires Runtime authentication; remove --insecure"); @@ -5918,7 +5918,7 @@ pub(crate) fn runtime_chat_relay_catalog( .bytes() .all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'_' | b'-')) { - return Err("Codewhale returned an invalid Runtime Chat relay challenge.".to_string()); + return Err("codewhale returned an invalid Runtime Chat relay challenge.".to_string()); } let provider = config.api_provider(); diff --git a/crates/tui/src/settings.rs b/crates/tui/src/settings.rs index c02fcb1795..6e52e2e016 100644 --- a/crates/tui/src/settings.rs +++ b/crates/tui/src/settings.rs @@ -1855,7 +1855,7 @@ impl Settings { ), ( "theme", - "UI theme: a compiled name or custom: from the Codewhale themes directory", + "UI theme: a compiled name or custom: from the codewhale themes directory", ), ( "background_color", diff --git a/crates/tui/src/skill_state.rs b/crates/tui/src/skill_state.rs index 26c3c687e2..2df9a542e6 100644 --- a/crates/tui/src/skill_state.rs +++ b/crates/tui/src/skill_state.rs @@ -118,7 +118,7 @@ fn default_state_path() -> Result { // Listing, prompt construction, and doctor are read-only. The explicit // mutation path creates the parent from `persist` when needed. Ok(codewhale_config::codewhale_home() - .context("could not resolve Codewhale state directory")? + .context("could not resolve codewhale state directory")? .join(STATE_FILE_NAME)) } diff --git a/crates/tui/src/tools/subagent/mod.rs b/crates/tui/src/tools/subagent/mod.rs index 7df3790097..6542960665 100644 --- a/crates/tui/src/tools/subagent/mod.rs +++ b/crates/tui/src/tools/subagent/mod.rs @@ -9355,7 +9355,7 @@ fn enforce_fleet_member_route_requirements( codewhale_config::route::CapabilityState::Supported => unreachable!(), }; return Err(ToolError::execution_failed(format!( - "Fleet member '{member_id}' requires vision, but exact route {provider_id}/{model_id} has image_input={state}. Codewhale will not reroute a capability-bound member; pin an exact route with verified image_input support." + "Fleet member '{member_id}' requires vision, but exact route {provider_id}/{model_id} has image_input={state}. codewhale will not reroute a capability-bound member; pin an exact route with verified image_input support." ))); } } diff --git a/crates/tui/src/tui/ui/apply.rs b/crates/tui/src/tui/ui/apply.rs index 343153b78f..9e2f68bc7b 100644 --- a/crates/tui/src/tui/ui/apply.rs +++ b/crates/tui/src/tui/ui/apply.rs @@ -3256,7 +3256,7 @@ pub(crate) fn apply_loaded_session_with_goal( ) .map_err(|reason| { format!( - "saved session provider '{}' could not be resolved from the live config: {reason}. Codewhale will not fall back", + "saved session provider '{}' could not be resolved from the live config: {reason}. codewhale will not fall back", provider_identity.key ) })?; diff --git a/crates/tui/src/tui/ui/event_loop.rs b/crates/tui/src/tui/ui/event_loop.rs index e843f765f3..17221fdef8 100644 --- a/crates/tui/src/tui/ui/event_loop.rs +++ b/crates/tui/src/tui/ui/event_loop.rs @@ -1281,7 +1281,7 @@ pub(crate) async fn run_event_loop( if let Err(err) = completion { tracing::warn!(error = %err, "background terminal clipboard write failed"); app.push_status_toast( - format!("Clipboard copy failed: {err}"), + format!("Couldn't copy: {err}"), StatusToastLevel::Error, None, ); diff --git a/crates/tui/src/tui/ui/handlers.rs b/crates/tui/src/tui/ui/handlers.rs index 7a2ccadd76..0dcef21b70 100644 --- a/crates/tui/src/tui/ui/handlers.rs +++ b/crates/tui/src/tui/ui/handlers.rs @@ -1275,7 +1275,7 @@ pub(crate) async fn handle_view_events( } ViewEvent::SessionDeleted { session_id, title } => { app.status_message = Some(format!( - "Deleted session {} ({})", + "Deleted {} ({})", crate::session_manager::truncate_id(&session_id), title )); diff --git a/crates/tui/src/tui/ui/tests.rs b/crates/tui/src/tui/ui/tests.rs index 23da8e8cd3..815f5052a9 100644 --- a/crates/tui/src/tui/ui/tests.rs +++ b/crates/tui/src/tui/ui/tests.rs @@ -9621,7 +9621,7 @@ fn manual_compaction_queues_once_after_active_turn_without_blocking() { ); assert_eq!( app.status_message.as_deref(), - Some("Context compaction queued; it will run after the active turn.") + Some("Compaction queued — runs after this turn.") ); match engine.rx_op.try_recv().expect("one queued compact op") { crate::core::ops::Op::CompactContext { compaction, .. } => { @@ -9640,7 +9640,7 @@ fn manual_compaction_queues_once_after_active_turn_without_blocking() { ); assert_eq!( app.status_message.as_deref(), - Some("Context compaction is already in progress.") + Some("Compaction is already running.") ); } @@ -9667,14 +9667,14 @@ fn full_engine_mailbox_defers_manual_compaction_and_flushes_once_drained() { assert!(app.deferred_manual_compaction.is_some()); assert_eq!( app.status_message.as_deref(), - Some("Context compaction queued; it will run after the active turn.") + Some("Compaction queued — runs after this turn.") ); // A repeat during deferral is the single queued pass, not a second one. try_queue_manual_compaction(&mut app, &config, &engine.handle, None); assert_eq!( app.status_message.as_deref(), - Some("Context compaction is already in progress.") + Some("Compaction is already running.") ); // The mailbox is still full: the flush waits without dropping the request. @@ -9749,7 +9749,7 @@ fn closed_engine_mailbox_reports_manual_compaction_unavailable() { assert!(!app.manual_compaction_queued); assert!(app.sticky_status.as_ref().is_some_and(|toast| { - toast.level == StatusToastLevel::Error && toast.text.contains("engine is no longer running") + toast.level == StatusToastLevel::Error && toast.text.contains("the engine stopped") })); } @@ -9761,7 +9761,7 @@ fn compaction_lifecycle_keeps_truthful_auto_label_until_matching_completion() { assert!(app.is_compacting); assert_eq!( app.status_message.as_deref(), - Some("Context automatically compacting…") + Some("Auto-compacting context…") ); assert_eq!( app.active_compaction @@ -9782,7 +9782,7 @@ fn compaction_lifecycle_keeps_truthful_auto_label_until_matching_completion() { assert!(app.is_compacting, "stale id must not clear newer activity"); assert_eq!( app.status_message.as_deref(), - Some("Context automatically compacting…") + Some("Auto-compacting context…") ); apply_compaction_completed( @@ -15075,7 +15075,7 @@ async fn steer_failure_queues_message_and_surfaces_toast() { assert_eq!(app.queued_message_count(), 1); let toast = app.status_toasts.back().expect("steer failure toast"); assert_eq!(toast.level, StatusToastLevel::Warning); - assert!(toast.text.contains("Could not send into this turn")); + assert!(toast.text.contains("Couldn't send into this turn")); } #[tokio::test] @@ -15100,7 +15100,7 @@ async fn streaming_enter_queue_pushes_visible_toast() { assert_eq!(app.queued_message_count(), 1); let toast = app.status_toasts.back().expect("queue toast"); assert_eq!(toast.level, StatusToastLevel::Info); - assert!(toast.text.contains("Queued. Sends after this turn.")); + assert!(toast.text.contains("Queued — sends after this turn.")); } #[test] @@ -15201,7 +15201,7 @@ async fn operate_streaming_enter_queues_another_parallel_task() { assert_eq!(app.queued_message_count(), 1); let toast = app.status_toasts.back().expect("Operate queue toast"); assert_eq!(toast.level, StatusToastLevel::Info); - assert_eq!(toast.text, "Queued. Sends after this turn."); + assert_eq!(toast.text, "Queued — sends after this turn."); assert_eq!(app.status_message.as_deref(), Some(toast.text.as_str())); } diff --git a/crates/tui/src/tui/views/fleet_list.rs b/crates/tui/src/tui/views/fleet_list.rs index 94544e35de..51094503d7 100644 --- a/crates/tui/src/tui/views/fleet_list.rs +++ b/crates/tui/src/tui/views/fleet_list.rs @@ -156,7 +156,7 @@ impl FleetListView { ), }), Err(err) => Some(FleetListOutcome::Done { - message: format!("Delete failed: {err}"), + message: format!("Could not delete: {err}"), }), } } diff --git a/crates/tui/src/tui/widgets/pending_input_preview.rs b/crates/tui/src/tui/widgets/pending_input_preview.rs index 6b9405ca96..4485480481 100644 --- a/crates/tui/src/tui/widgets/pending_input_preview.rs +++ b/crates/tui/src/tui/widgets/pending_input_preview.rs @@ -592,7 +592,7 @@ mod tests { "pending-input copy leaked internal vocabulary: {joined}" ); assert!(joined.contains("sending into this turn")); - assert!(joined.contains("could not send into this turn")); + assert!(joined.contains("held for next turn")); } #[test] @@ -612,7 +612,7 @@ mod tests { ); assert!( rows.iter() - .any(|row| row.contains("Could not send into this turn: rejected")), + .any(|row| row.contains("Held for next turn: rejected")), "missing rejected send-now label: {rows:?}" ); assert!( From a00a8a24322348e9a68b14280e9d56db02f23483 Mon Sep 17 00:00:00 2001 From: CodeWhale Bot Date: Wed, 2 Sep 2026 13:43:50 -0700 Subject: [PATCH 2/3] copy(pickers): clearer picker, config, and plugin copy Rewrite picker/menu/config/fleet/provider/plugin copy in en.json (shorter, warmer; product name lowercased to codewhale) and sync the inline translate() fallbacks plus registry strings that render the same copy. Keys, placeholders, and parsed punctuation unchanged; test-pinned phrases (session-model-only, context length/size, provider rejection wording) preserved. Tests: 1401 targeted pass; 65 locale goldens pass; cargo fmt clean; check-tui-product-vocabulary.sh clean. --- crates/tui/locales/en.json | 450 +++++++++--------- crates/tui/src/commands/groups/core/core.rs | 4 +- .../tui/src/commands/groups/plugins/tests.rs | 2 +- crates/tui/src/commands/groups/utility/mcp.rs | 19 +- crates/tui/src/localization.rs | 2 +- crates/tui/src/tui/approval/elevation.rs | 10 +- crates/tui/src/tui/context_inspector.rs | 4 +- crates/tui/src/tui/hotbar/actions.rs | 8 +- crates/tui/src/tui/keybindings.rs | 2 +- crates/tui/src/tui/provider_picker.rs | 6 +- crates/tui/src/tui/ui/event_loop.rs | 2 +- crates/tui/src/tui/views/mod.rs | 6 +- 12 files changed, 255 insertions(+), 260 deletions(-) diff --git a/crates/tui/locales/en.json b/crates/tui/locales/en.json index b71f5f472d..aeb267a2d3 100644 --- a/crates/tui/locales/en.json +++ b/crates/tui/locales/en.json @@ -14,7 +14,7 @@ "ExtensionsComponentBrowserDriver": "browser driver", "ExtensionsComponentNativeRuntime": "native runtime", "ExtensionsComponentSandboxRuntime": "sandbox runtime", - "ExtensionsGroupBuiltIn": "Built in", + "ExtensionsGroupBuiltIn": "Built-in", "ExtensionsGroupConfigured": "Configured", "ExtensionsGroupProblems": "Problems", "ExtensionsGroupRecommended": "Recommended", @@ -32,12 +32,12 @@ "ExtensionsInventoryNone": "No supported components", "ExtensionsInventorySkills": "Skills: {count}", "ExtensionsMarketplaceDetail": "publisher: {publisher} · tier: {tier} · installable: {installable}", - "ExtensionsMarketplaceUnavailable": "Plugin marketplace storage is unavailable", + "ExtensionsMarketplaceUnavailable": "Marketplace storage unavailable", "ExtensionsMcpDetail": "tools: {tools} · resources: {resources} · prompts: {prompts}", - "ExtensionsMcpNotInspected": "Not inspected in this snapshot · Reload required to connect configured servers", - "ExtensionsMcpRefresh": "{count} MCP servers configured; open /mcp to refresh this snapshot", + "ExtensionsMcpNotInspected": "Not inspected yet · reload to connect your servers", + "ExtensionsMcpRefresh": "{count} MCP servers set up; open /mcp to refresh", "ExtensionsMcpSummary": "{transport} · tools: {tools} · resources: {resources}", - "ExtensionsNoItems": "No items on this tab", + "ExtensionsNoItems": "Nothing on this tab", "ExtensionsNoMatches": "No matches for '{query}'", "ExtensionsPluginDetail": "{inventory} · trust: {trust} · compatibility: {compatibility} · diagnostics: {diagnostics}", "ExtensionsProductBrowserUseDescription": "Browser-control workflow packaged as an agent Skill.", @@ -50,8 +50,8 @@ "ExtensionsSkillRootCompatibleGlobal": "Compatible global ({harness})", "ExtensionsSkillRootCompatibleProject": "Compatible project ({harness})", "ExtensionsSkillRootConfigured": "Configured directory", - "ExtensionsSkillRootGlobal": "Global Codewhale skills", - "ExtensionsSkillRootProject": "Project Codewhale skills", + "ExtensionsSkillRootGlobal": "Global codewhale skills", + "ExtensionsSkillRootProject": "Project codewhale skills", "ExtensionsSkillRootRegistryCache": "Registry cache", "ExtensionsSkillRootReviewedPlugin": "Reviewed plugin", "ExtensionsStateAvailable": "available", @@ -116,8 +116,8 @@ "ComposerDispatchFailedRestored": "Not sent ({error}) — draft restored to the composer.", "DispatchFailedQueued": "Send failed ({error}); kept {count} queued follow-up(s).", "DispatchFailedInitial": "Could not send your first message: {error}", - "HistorySearchPlaceholder": "Search prompt history...", - "HistorySearchTitle": "History Search", + "HistorySearchPlaceholder": "Search history...", + "HistorySearchTitle": "History search", "HistoryHintMove": "Up/Down move", "HistoryHintAccept": "Enter accept", "HistoryHintRestore": "Esc restore", @@ -141,7 +141,7 @@ "TelemetryPreferenceDisabledForSession": "Counting is off for this session. The choice couldn't be saved, so it returns next launch: {detail}", "TelemetryPreferenceSaveFailed": "Could not save the telemetry choice: {detail}", "StatusPickerTitle": " Status line ", - "StatusPickerInstruction": "Pick the chips you want in the footer:", + "StatusPickerInstruction": "Choose what the footer shows:", "StatusPickerActionToggle": "toggle ", "StatusPickerActionAll": "all ", "StatusPickerActionNone": "none ", @@ -160,17 +160,17 @@ "HotbarSetupDirtyClean": "clean", "HotbarSetupNoAction": "No action", "HotbarSetupStatusLine": "slot {slot} | {action} | {dirty}", - "HotbarSetupSlotOutOfRange": "Hotbar slot {slot} is outside 1-{max}", - "HotbarSetupNoActionSelected": "No action selected.", + "HotbarSetupSlotOutOfRange": "Slot {slot} must be 1-{max}", + "HotbarSetupNoActionSelected": "Pick an action first.", "HotbarSetupCannotAssign": "{action} cannot be assigned: {reason}", - "HotbarSetupNoActions": "No hotbar actions are available.", + "HotbarSetupNoActions": "No hotbar actions available.", "HotbarSetupRecommended": "rec", "HotbarSetupEmptySlot": "empty", "HotbarSetupHelp": "Tab/Shift+Tab source Up/Down action 1-8 slot Enter assign Space toggle Delete clear s save Esc cancel", "HotbarActionVoiceToggleName": "Voice input", - "HotbarActionVoiceToggleDescription": "Toggle voice capture from the terminal microphone.", + "HotbarActionVoiceToggleDescription": "Talk instead of type — uses your microphone.", "HotbarActionSessionCompactName": "Compact session", - "HotbarActionSessionCompactDescription": "Compact the current conversation context.", + "HotbarActionSessionCompactDescription": "Shrink this conversation to free context.", "HotbarActionModePlanName": "Plan mode", "HotbarActionModePlanDescription": "Think through a plan before acting.", "HotbarActionModeAgentName": "Work mode", @@ -178,7 +178,7 @@ "HotbarActionModeYoloName": "Full Access (Act)", "HotbarActionModeYoloDescription": "Compatibility: Act with Full Access permissions (not a separate mode).", "HotbarActionReasoningCycleName": "Cycle reasoning", - "HotbarActionReasoningCycleDescription": "Cycle the configured reasoning effort for the active provider.", + "HotbarActionReasoningCycleDescription": "Step through reasoning levels for the active provider.", "HotbarActionReasoningCycleAutoDisabled": "Reasoning effort is controlled by auto model routing.", "HotbarActionSidebarToggleName": "Toggle sidebar", "HotbarActionSidebarToggleDescription": "Show or hide the sidebar.", @@ -187,10 +187,10 @@ "HotbarActionPaletteOpenName": "Command palette", "HotbarActionPaletteOpenDescription": "Open the command palette.", "HotbarActionTrustToggleName": "Toggle trust", - "HotbarActionTrustToggleDescription": "Enable or disable workspace trust mode.", + "HotbarActionTrustToggleDescription": "Turn workspace trust on or off.", "ConfigTitle": "Config", "ConfigPreviewLabel": "Preview: ", - "ConfigHintExternalCredentials": "Which credential file this provider may read, at what access, and how to revoke it.", + "ConfigHintExternalCredentials": "Which credential file this provider may read, and how to revoke it.", "ConfigModalTitle": " Config ", "ConfigSearchPlaceholder": "type to filter", "ConfigNoSettings": " No settings available.", @@ -218,15 +218,15 @@ "ConfigScopeSaved": "SAVED", "ConfigCommandSource": "{value} (source: {source})", "ConfigCommandInvalidValue": "Can't use '{value}' for {key}. Try: {choices}.", - "ConfigSearchUpdated": "search.provider = {value} ({scope}; subsequent web_search calls use the effective provider after environment overrides)", - "ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; ghost-text hints apply after subsequent turns)", + "ConfigSearchUpdated": "search.provider = {value} ({scope}; later web_search calls use the effective provider)", + "ConfigPromptSuggestionUpdated": "prompt_suggestion = {value} ({scope}; ghost text applies from next turn)", "ConfigNotificationsSetHint": "Set with /config notifications [--save].", - "ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; applies to subsequent alerts)", + "ConfigNotificationUpdated": "notifications.{key} = {value} ({scope}; applies to later alerts)", "ConfigNotificationsWholeNumber": "notifications.threshold_secs must be a whole number", "ConfigAuditSearchProvider": "Writes [search] provider; subsequent web_search calls still honor environment overrides.", "ConfigAuditPromptSuggestion": "Writes top-level prompt_suggestion; ghost-text hints stay opt-in.", "ConfigAuditNotifications": "Writes [notifications] scalars and applies them to subsequent turn-complete alerts.", - "ConfigHelpDiscoverable": " Discoverable config.toml keys: `/config search.provider`, `/config prompt_suggestion`, `/config notifications`. Use `--save` to persist.", + "ConfigHelpDiscoverable": " Also settable: `/config search.provider`, `/config prompt_suggestion`, `/config notifications`. Add `--save` to persist.", "ConfigEditCancelled": "Edit cancelled", "ConfigEditTitlePrefix": "Edit ", "ConfigEditScopeLabel": "Scope: ", @@ -256,7 +256,7 @@ "ConfigLabelAllowShell": "Shell access", "ConfigLabelManagedAllowShell": "Shell access (managed)", "ConfigLabelTelemetry": "Anonymous usage counts", - "ConfigHintTelemetry": "Saved preference for anonymous feature and error counts; never conversations or code", + "ConfigHintTelemetry": "Saved choice for anonymous counts; never conversations or code", "ConfigValueTelemetryOn": "On (saved)", "ConfigValueTelemetryOff": "Off (saved)", "ConfigLabelStreamTimeout": "Stream timeout", @@ -271,10 +271,10 @@ "ConfigLabelLowMotion": "Reduce motion", "ConfigLabelFancyAnimations": "Live UI motion", "ConfigLabelLaunchScreen": "Launch screen", - "ScreenModeFullscreenNotice": "Screen: fullscreen (alternate screen).", - "ScreenModeInlineNotice": "Screen: inline — the terminal keeps its own scrollback. The transcript stays in the viewport; nothing is written into scrollback yet.", + "ScreenModeFullscreenNotice": "Screen: fullscreen.", + "ScreenModeInlineNotice": "Screen: inline — the terminal keeps its scrollback; the transcript stays in view.", "ScreenModeMouseCaptureOn": "Mouse capture on.", - "ScreenModeMouseCaptureOff": "Mouse capture off; the terminal owns selection.", + "ScreenModeMouseCaptureOff": "Mouse off — the terminal owns selection.", "ScreenModeUnchanged": "Screen unchanged: {reason}.", "ImageInputRejectedResent": "{model} does not accept images — resent as text; use image_ocr to read them", "ConfigLabelShowThinking": "Model reasoning in chat", @@ -408,23 +408,23 @@ "CmdLspDescription": "Toggle LSP diagnostics on or off", "CmdShareDescription": "Export current session as a shareable web URL", "CmdJobsDescription": "Inspect and control background Bash jobs", - "CmdDispatchDescription": "Send a Codewhale cloud agent to raise a branch and open a PR", - "CmdLinksDescription": "Show Codewhale, community, and provider links", + "CmdDispatchDescription": "Send a codewhale cloud agent to raise a branch and open a PR", + "CmdLinksDescription": "Show codewhale, community, and provider links", "CmdLoadDescription": "Load session from file", "CmdLogoutDescription": "Clear API key and return to setup", "CmdMcpDescription": "Open or manage MCP servers", - "McpRecommendedUnknownId": "Unknown recommended MCP ID. Run {recommendations_command} to inspect the curated list.", - "McpRecommendationsHeading": "Suggested Codewhale plugins (MCP components; nothing is installed automatically)", - "McpRecommendationsSafety": "Viewing this list adds or enables nothing. An explicit add writes config only; review it before {restart_command} connects the server.", - "McpRecommendationGithub": "• github — GitHub's official remote MCP endpoint\n endpoint: {endpoint}\n auth is separate: use {login_command} only when the server advertises OAuth;\n otherwise configure a least-privilege PAT outside command history. Granted\n scopes may write or delete repository data, so start read-only where possible.\n add explicitly: {add_command}", - "McpRecommendationChrome": "• chrome-devtools — official Chrome DevTools MCP via pinned npm package\n package: {package} ({launcher})\n it can inspect/control Chrome and read authenticated pages. Close sensitive\n tabs and verify the package before adding; {restart_command} may download and run it.\n add explicitly: {add_command}", - "McpRecommendationPlaywright": "• playwright — Microsoft's official Playwright MCP via pinned npm package\n package: {package} ({launcher})\n source: {source}\n --isolated starts a fresh browser profile. It can browse/control pages and submit\n forms, so review actions first; {restart_command} may download and run the package.\n add explicitly: {add_command}", - "McpRecommendationCua": "• cua — Cua Driver computer-use plugin (MCP server component)\n command: cua-driver mcp\n source: {source}\n preview: install and verify Cua Driver separately; Codewhale never downloads it. It can\n control the desktop and needs operating-system permissions. Review both before {restart_command}.\n add explicitly: {add_command}", - "McpRecommendationContainerUse": "• container-use — Dagger's experimental container-use MCP\n command: container-use stdio\n source: {source}\n requires the separately installed container-use binary; Codewhale never downloads or\n installs this binary. It can create containers and change mounted workspace files.\n Review the install and command before {restart_command}.\n add explicitly: {add_command}", - "CmdPluginDescription": "Inspect and manage trusted plugin bundles; legacy executable tools stay separate", - "PluginKimiUsage": "Usage:\n {list_command}\n {approve_command}\nListing is read-only. Approval copies one canonical Kimi-managed plugin through the reviewed installer; it remains disabled and untrusted.", + "McpRecommendedUnknownId": "Unknown MCP suggestion. Run {recommendations_command} to see the list.", + "McpRecommendationsHeading": "Suggested codewhale plugins (MCP components; nothing installs automatically)", + "McpRecommendationsSafety": "Looking adds nothing. Adding writes config only — review it before {restart_command} connects anything.", + "McpRecommendationGithub": "• github — GitHub's official remote MCP endpoint\n endpoint: {endpoint}\n auth is separate: {login_command} only for advertised OAuth;\n otherwise set a least-privilege PAT outside history. Scopes\n can write or delete repo data, so start read-only.\n add explicitly: {add_command}", + "McpRecommendationChrome": "• chrome-devtools — official Chrome DevTools MCP (pinned npm package)\n package: {package} ({launcher})\n it can drive Chrome and read signed-in pages. Close sensitive\n tabs and verify the package first; {restart_command} may download and run it.\n add explicitly: {add_command}", + "McpRecommendationPlaywright": "• playwright — Microsoft's official Playwright MCP (pinned npm package)\n package: {package} ({launcher})\n source: {source}\n --isolated starts a fresh browser profile. It can drive pages and submit\n forms, so review actions first; {restart_command} may download and run the package.\n add explicitly: {add_command}", + "McpRecommendationCua": "• cua — Cua Driver computer-use plugin (MCP server component)\n command: cua-driver mcp\n source: {source}\n preview: install and verify Cua Driver separately; codewhale never downloads it. It can\n control the desktop and needs operating-system permissions. Review both before {restart_command}.\n add explicitly: {add_command}", + "McpRecommendationContainerUse": "• container-use — Dagger's experimental container-use MCP\n command: container-use stdio\n source: {source}\n requires the separately installed container-use binary; codewhale never downloads or\n installs this binary. It can create containers and change mounted workspace files.\n Review the install and command before {restart_command}.\n add explicitly: {add_command}", + "CmdPluginDescription": "Manage trusted plugin bundles (legacy tools stay separate)", + "PluginKimiUsage": "Usage:\n {list_command}\n {approve_command}\nListing changes nothing. Approval copies one plugin through the reviewed installer; it stays disabled and untrusted.", "PluginKimiManagedRootHeading": "Kimi-managed plugins at {root}:", - "PluginKimiNoneFound": "No valid managed plugins found.", + "PluginKimiNoneFound": "No managed plugins found.", "PluginKimiLicenseUnspecified": "unspecified", "PluginKimiApplicable": "applicable on this OS", "PluginKimiNotApplicable": "not applicable on this OS", @@ -432,39 +432,39 @@ "PluginKimiCandidateDetails": " path: {path}\n content hash: {content_hash}\n capability hash: {capability_hash}\n approve: {approve_command}", "PluginKimiRejectedHeading": "Rejected entries (not importable):", "PluginKimiInspectionFooter": "This inspection did not copy, trust, enable, or execute anything. External Kimi apps, daemons, binaries, browser extensions, credentials, and OS permissions were not checked.", - "PluginKimiCandidateMissing": "No valid canonical Kimi-managed plugin named `{name}`. Run {list_command} again.", - "PluginKimiCandidateChanged": "Kimi-managed plugin `{name}` changed since review. Expected content hash {expected}, now {actual}. Nothing was copied; run {list_command} again.", - "PluginKimiHomeMissing": "Cannot locate the user home directory for Kimi import.", - "PluginKimiRootInspectFailed": "Cannot inspect Kimi managed plugin root {root}: {error}", - "PluginKimiRootMustBeDirectory": "Kimi managed plugin root {root} must be a real directory, not a link or reparse point.", - "PluginKimiRootCanonicalizeFailed": "Cannot canonicalize Kimi managed plugin root {root}: {error}", - "PluginKimiRootListFailed": "Cannot list Kimi managed plugin root {root}: {error}", - "PluginKimiEntryReadFailed": "Cannot read a Kimi managed plugin entry: {error}", - "PluginKimiEntryLimit": "Kimi managed plugin root contains {count} entries; the maximum reviewed in one scan is {max}.", - "PluginKimiEntryInspectFailed": "{path}: cannot inspect: {error}", + "PluginKimiCandidateMissing": "No managed plugin named `{name}`. Run {list_command} again.", + "PluginKimiCandidateChanged": "Plugin `{name}` changed since review (expected {expected}, now {actual}). Nothing was copied; run {list_command} again.", + "PluginKimiHomeMissing": "Can't find your home directory for Kimi import.", + "PluginKimiRootInspectFailed": "Can't inspect plugin root {root}: {error}", + "PluginKimiRootMustBeDirectory": "Plugin root {root} must be a real folder, not a link.", + "PluginKimiRootCanonicalizeFailed": "Can't resolve plugin root {root}: {error}", + "PluginKimiRootListFailed": "Can't list plugin root {root}: {error}", + "PluginKimiEntryReadFailed": "Can't read a plugin entry: {error}", + "PluginKimiEntryLimit": "Plugin root holds {count} entries; one scan reviews at most {max}.", + "PluginKimiEntryInspectFailed": "{path}: can't inspect: {error}", "PluginKimiEntryLinksRefused": "{path}: links and reparse points are refused", - "PluginKimiEntryOutsideRoot": "{path}: canonical path {canonical_path} is not an immediate child of the managed root", - "PluginKimiEntryCanonicalizeFailed": "{path}: cannot canonicalize: {error}", - "PluginKimiManifestUnreadable": "{path}: no readable {manifest}: {error}", - "PluginKimiManifestMustBeFile": "{path}: {manifest} must be a real regular file", + "PluginKimiEntryOutsideRoot": "{path}: {canonical_path} isn't directly inside the managed root", + "PluginKimiEntryCanonicalizeFailed": "{path}: can't resolve: {error}", + "PluginKimiManifestUnreadable": "{path}: can't read {manifest}: {error}", + "PluginKimiManifestMustBeFile": "{path}: {manifest} must be a plain file", "PluginKimiManifestInvalid": "{path}: invalid manifest: {error}", - "PluginKimiDirectoryNameMismatch": "{path}: directory name must exactly match manifest name `{name}`", + "PluginKimiDirectoryNameMismatch": "{path}: folder name must match `{name}` exactly", "PluginKimiHashUnavailable": "unavailable", - "PluginKimiRollbackDestinationMissing": "The installer did not report the destination path.", - "PluginKimiMismatchRemoved": "Plugin `{name}` did not match the approved content after copying (expected {expected}, found {actual}). The unexpected copy was removed; review and retry.", - "PluginKimiMismatchRollbackFailed": "Error: Plugin `{name}` did not match the approved content after copying (expected {expected}, found {actual}), and automatic removal failed: {error}. It remains disabled and untrusted; inspect {path} before taking further action.", + "PluginKimiRollbackDestinationMissing": "The installer never reported where it wrote.", + "PluginKimiMismatchRemoved": "Plugin `{name}` changed in transit (expected {expected}, found {actual}). The bad copy was removed; review and retry.", + "PluginKimiMismatchRollbackFailed": "Plugin `{name}` changed in transit (expected {expected}, found {actual}), and cleanup failed: {error}. It stays disabled and untrusted; inspect {path} first.", "PluginKimiUserPluginDirectory": "the user plugin directory", - "PluginKimiMarketplaceZipUnsupported": "Kimi ZIP bundles are not supported by Codewhale's reviewed installer; install from a local directory or import an upstream Kimi-managed plugin.", - "PluginKimiMarketplaceRemoteUnsupported": "Kimi remote sources must end in .tar.gz or .tgz for Codewhale installation; .zip is recognized but not supported.", + "PluginKimiMarketplaceZipUnsupported": "Kimi ZIP bundles are not supported by codewhale's reviewed installer; install from a local directory or import an upstream Kimi-managed plugin.", + "PluginKimiMarketplaceRemoteUnsupported": "Kimi remote sources must end in .tar.gz or .tgz for codewhale installation; .zip is recognized but not supported.", "PluginKimiMarketplaceGzipTarball": "gzip tarball URL", "CmdPluginBundleUsage": "Usage: /plugin [list|show |validate [name]|export |install |update |uninstall |trust [review-token]|enable |disable |revoke |reload|tools [name]]", - "CmdPluginBundleNoneFound": "No Codewhale plugin bundles discovered.", + "CmdPluginBundleNoneFound": "No codewhale plugin bundles found.", "CmdPluginBundleListHeader": "Plugin bundles ({count}):", - "CmdPluginLegacyListHeader": "Legacy executable plugin tools ({count}) in {dir}:", - "CmdPluginBundleNotFound": "Plugin bundle '{name}' not found", - "CmdPluginBundleReloaded": "Reloaded {count} plugin bundles for {workspace}.", - "PluginPromptSuggestTrust": "This looks like {name} work. Review it with /plugin trust {name} before enabling.", - "PluginPromptSuggestEnable": "This looks like {name} work. Enable it with /plugin enable {name}.", + "CmdPluginLegacyListHeader": "Legacy plugin tools ({count}) in {dir}:", + "CmdPluginBundleNotFound": "No plugin bundle named '{name}'", + "CmdPluginBundleReloaded": "Reloaded {count} bundles for {workspace}.", + "PluginPromptSuggestTrust": "This looks like {name} work — run /plugin trust {name} before enabling.", + "PluginPromptSuggestEnable": "This looks like {name} work — enable it with /plugin enable {name}.", "PluginPromptSuggestMarketplace": "This looks like {name} work. Install it from catalog `{catalog}` with /plugin marketplace install {catalog} {name}.", "PluginCtaInstallPrompt": "Install {name} plugin?", "PluginCtaReview": "Review", @@ -472,9 +472,9 @@ "CmdPluginBundleDetail": "{name}\n========================================\nID: {id}\nVersion: {version}\nSource: {origin} ({scope})\nState: {state}\nTrust: {trust}\nComponents: {inventory}\nRequested permissions: {permissions}\nMCP servers: {mcp}\nUnsupported/inactive: {unsupported}\nContent hash: {content_hash}\nCapability hash: {capability_hash}\nPath: {path}", "CmdPluginBundleDiagnosticsHeader": "Plugin diagnostics ({count}):", "CmdPluginBundleMutationSuccess": "Plugin bundle '{name}': {action}.", - "CmdPluginActionFailed": "Plugin action failed: {error}", - "CmdPluginNoneFound": "No legacy executable plugin tools discovered in {dir}", - "CmdPluginNotFound": "Plugin '{name}' not found", + "CmdPluginActionFailed": "Plugin action didn't finish: {error}", + "CmdPluginNoneFound": "No legacy plugin tools in {dir}", + "CmdPluginNotFound": "No plugin named '{name}'", "CmdPluginListHeader": "Legacy executable plugin tools ({count}):", "CmdPluginDetailDescription": "Description: {description}", "CmdPluginDetailSchema": "Schema:\n{schema}", @@ -486,12 +486,12 @@ "CmdModelsDescription": "Fetch live model IDs from the active API", "CmdModelDbDescription": "Browse the bundled model database", "CmdNetworkDescription": "Manage network allow and deny rules", - "CmdUpdateDescription": "Check for and install a new Codewhale release", + "CmdUpdateDescription": "Check for and install a new codewhale release", "CmdNoteDescription": "Add, list, edit, or remove workspace notes", "CmdThemeDescription": "Switch theme or open the theme picker", "CmdProviderDescription": "Switch the active provider and/or model", "CmdAuthDescription": "Manage provider authentication flows", - "CmdLoginDescription": "Sign in to Codewhale or store provider keys", + "CmdLoginDescription": "Sign in to codewhale or store provider keys", "CmdQueueDescription": "View or edit queued messages", "CmdQueueUsage": "Usage: /queue [list|send |edit |drop |clear]", "CmdQueueDraftHeader": "Editing queued message:", @@ -509,7 +509,7 @@ "CmdQueueIndexPositive": "Index must be a positive number", "CmdQueueIndexMin": "Index must be >= 1", "CmdRelayDescription": "Create a session relay (接力) for a fresh thread", - "CmdRemoteControlDescription": "Resume this exact session from your Codewhale web account", + "CmdRemoteControlDescription": "Resume this exact session from your codewhale web account", "CmdRemoteEnvDescription": "Open new hosted Work from a GitHub or CNB branch tip", "CmdRemoteEnvOverview": "Hosted Work starts a new environment from the branch tip available at GitHub or CNB.\n\nIt does not move this local folder or include unpushed commits, dirty or ignored files, secrets, or session state.\n\nUse {command} to open the hosted Work launcher.", "CmdRemoteEnvOpening": "Opening hosted Work for {repo} on branch {branch}.\n\nThis starts a new environment from the branch tip available at the Git host configured as {origin}. Local-only state is not included.\n\nIf the browser does not open, use:\n{url}", @@ -657,11 +657,11 @@ "KbAltJumpPlanAgentYolo": "Jump to Plan / Work, or request Full Access (legacy alias, not a mode)", "KbFocusSidebar": "Focus the Tasks / Agents / Context / Pinned rail panel", "KbSessionPicker": "Open the session picker", - "KbUpdateInstall": "Check for and install the latest Codewhale update (`/update install`)", - "UpdateChangedHint": "Codewhale was updated: {previous} → {current}. Run /change to see what's new.", + "KbUpdateInstall": "Check for and install the latest codewhale update (`/update install`)", + "UpdateChangedHint": "Updated codewhale: {previous} → {current}. Run /change to see what's new.", "KbTerminalPaste": "Paste text using your local terminal", "KbPasteAttach": "Paste text or attach an image from a local or forwarded graphical clipboard", - "KbCopySelection": "Copy the current Codewhale selection", + "KbCopySelection": "Copy the current codewhale selection", "ClipboardSshPasteHint": "SSH paste uses your local terminal: press Cmd+V on macOS or Ctrl+Shift+V on Linux/Windows.", "KbContextMenu": "Open context actions for paste, selection, message details, context, and help", "KbAttachPath": "Add a local text file or directory to context", @@ -673,7 +673,7 @@ "SettingsTitle": "Settings:", "SettingsConfigFile": "Config file:", "ClearConversation": "Conversation cleared", - "ClearConversationBusy": "Still busy — nothing cleared. Try /clear again in a moment.", + "ClearConversationBusy": "Nothing cleared — still busy. Try /clear again in a moment.", "ModelChanged": "Model changed: {old} →, {new}", "LinksProjectTitle": "Codewhale & community:", "LinksDocumentation": "Documentation:", @@ -686,12 +686,12 @@ "LinksDocs": "Docs:", "LinksKimiCodeRouteNote": "Kimi Code membership-plan route: `{route}` (plan console: `{console}`; use model k3). Codewhale never imports Kimi CLI credentials.", "LinksTip": "Tip: Use the env var shown for your provider, or save the key with `codewhale auth set --provider `.", - "SubagentsFetching": "Fetching current-session sub-agents...", - "SubagentsNoCurrentSessionPodWorkers": "No current-session fleet workers.", + "SubagentsFetching": "Finding this session's sub-agents...", + "SubagentsNoCurrentSessionPodWorkers": "No fleet workers this session.", "SubagentsCurrentSessionPodWorkersTitle": "Current-session fleet workers", - "SubagentsCurrentSessionPodWorkerRoles": "Sub-agent roles are current-session fleet worker roles.", - "SubagentsCurrentSessionPodWorkersStatus": "Current-session fleet workers: {count} total", - "SubagentsEmptyGuidance": "Configure roles and launch posture with /fleet.", + "SubagentsCurrentSessionPodWorkerRoles": "Roles for this session's fleet workers.", + "SubagentsCurrentSessionPodWorkersStatus": "Fleet workers this session: {count}", + "SubagentsEmptyGuidance": "Set up roles with /fleet.", "SubagentsStatusRunning": "Running", "SubagentsStatusCompleted": "Completed", "SubagentsStatusInterrupted": "Interrupted", @@ -728,7 +728,7 @@ "SubagentsRoleReviewer": "reviewer", "SubagentsRoleConsultant": "advisor", "SubagentsRoleCustom": "custom", - "HelpUnknownCommand": "Unknown command: {topic}", + "HelpUnknownCommand": "Unknown command: {topic} — try /help", "HomeDashboardTitle": "Codewhale", "HomeModel": "Model:", "HomeMode": "Mode:", @@ -736,7 +736,7 @@ "HomeHistory": "History:", "HomeTokens": "Tokens:", "HomeQueued": "Queued:", - "HomeSubagents": "Current-session fleet workers:", + "HomeSubagents": "Fleet workers this session:", "HomeSkill": "Skill:", "HomeQuickActions": "Quick Actions", "HomeQuickLinks": "/links - Codewhale, community & provider links", @@ -998,9 +998,9 @@ "CtxMenuHelpDesc": "keybindings and commands", "CtxMenuWindowPin": "Shrink and pin on top", "CtxMenuWindowUnpin": "Restore window", - "CmdPinDescription": "Pin/unpin the window as an always-on-top mini window", + "CmdPinDescription": "Pin this window on top", "CtxMenuWindowPinDesc": "pin/unpin this window on top", - "WindowPinActive": "Window pinned as always-on-top mini window", + "WindowPinActive": "Window pinned on top", "WindowPinReleased": "Window restored", "FanoutCounts": "{done} done · {running} running · {failed} failed · {pending} pending", "AppModeAgent": "Work", @@ -1043,7 +1043,7 @@ "ApprovalFullAccessPolicyBlocked": "Blocked {tool}: even Full Access must honor this policy", "AutoReviewQuestionSkipped": "Auto-Review skipped a user question and continued autonomously", "ApprovalChooseHint": "Choose: ", - "ApprovalChooseAction": "Enter selected option, or press y/a/d directly", + "ApprovalChooseAction": "Enter selects, or press y/a/d directly", "ApprovalIntentLabel": "Intent: ", "ApprovalMoreLines": " … (+{count} lines)", "ApprovalAutoDeniedSession": "Auto-denied {tool}: you denied a matching request earlier in this run. Restart codewhale to reconsider it.", @@ -1055,16 +1055,16 @@ "ElevationImpactHeader": " Impact if approved:", "ElevationImpactNetwork": " - network retry enables outbound downloads and HTTP requests", "ElevationImpactWrite": " - write retry expands writable filesystem scope for this tool call", - "ElevationImpactFullAccess": " - full access removes sandbox restrictions entirely for this retry", + "ElevationImpactFullAccess": " - full access drops all sandbox limits for this retry", "ElevationPromptProceed": " Choose how to proceed:", "ElevationOptionNetwork": "Allow outbound network", "ElevationOptionWrite": "Allow extra write access", "ElevationOptionFullAccess": "Full access (filesystem + network)", "ElevationOptionAbort": "Abort", - "ElevationOptionNetworkDesc": "Retry this tool call with outbound network access for downloads and HTTP requests", - "ElevationOptionWriteDesc": "Retry this tool call with additional writable filesystem scope", + "ElevationOptionNetworkDesc": "Retry with outbound network (downloads and HTTP)", + "ElevationOptionWriteDesc": "Retry with a wider writable scope", "ElevationOptionFullAccessDesc": "Retry without sandbox limits; grants unrestricted filesystem and network access", - "ElevationOptionAbortDesc": "Cancel this tool execution", + "ElevationOptionAbortDesc": "Cancel this run", "ContextAutoCompacting": "Auto-compacting context…", "ContextManualCompacting": "Compacting context…", "ContextCompactionQueued": "Compaction queued — runs after this turn.", @@ -1094,9 +1094,9 @@ "CtxInspOutputCaptured": "output captured", "CtxInspNoOutputYet": "no output yet", "CtxInspNoSystemPrompt": "No system prompt set.", - "CtxInspNoReferences": "No file, directory, or media references recorded yet.", - "CtxInspNoToolActivity": "No tool activity recorded yet.", - "CtxInspVHint": "Open the matching card and press {details} for full details.", + "CtxInspNoReferences": "No file, folder, or media references yet.", + "CtxInspNoToolActivity": "No tool activity yet.", + "CtxInspVHint": "Open the card and press {details} for full details.", "CtxInspCells": "cells", "CtxInspApiMessages": "API messages", "CtxInspActive": "active", @@ -1117,7 +1117,7 @@ "CtxInspCacheFriendly": "cache-friendly", "CtxInspChangesByTurn": "changes by session/turn", "CtxInspStablePrefixOnly": "stable prefix only", - "CtxInspCacheTip": "Tip: Stable prefix blocks are cache eligible when the active provider supports prefix caching. Volatile working-set changes break the cache only for the tail.", + "CtxInspCacheTip": "Tip: stable-prefix blocks can hit the cache when your provider supports it. Volatile tail changes break only the tail.", "ToolFamilyRead": "read", "ToolFamilyPatch": "patch", "ToolFamilyRun": "run", @@ -1156,16 +1156,16 @@ "NotificationSubagentBudgetExhausted": "Sub-agent budget exhausted", "FooterWorkedChip": "worked {duration}", "FleetDraftTitle": "fleet profile — draft by {model_label} (g saves)", - "FleetDraftHeader": "# .codewhale/agents/{name}\n# Drafted by {model_label}, validated and bounded by Codewhale.\n# Permissions stay at the fleet floor: no shell, no trust, approval required.\n# Nothing is saved until you press g in the wizard.\n\n", + "FleetDraftHeader": "# .codewhale/agents/{name}\n# Drafted by {model_label}, validated and bounded by codewhale.\n# Permissions stay at the fleet floor: no shell, no trust, approval required.\n# Nothing is saved until you press g in the wizard.\n\n", "SetupRemoteOnRampText": "Remote Runtime On-Ramp\n\n/setup shows remote runtime facts only. It does not generate deploy bundles, write credentials, call cloud CLIs, or run `remote-setup`.\n\nCurrent facts:\n- Clouds: {clouds_result}\n- Chat bridges: {bridges_result}\n- Providers: {providers_result}\n- Mode: {mode_result}\n\nTo generate a deploy bundle, run explicitly in a normal terminal:\n\n```sh\n{command}\n```\n\nThe generated RUNBOOK includes host steps for human review. `--apply` remains unimplemented; do not treat this as auto-deploy.", - "ApprovalDescSafe": "Requesting a safe/read-only operation.", - "ApprovalDescFileWrite": "Requesting to modify a file. Please confirm path and content.", - "ApprovalDescShell": "Requesting to execute a shell command. Review command and working directory.", - "ApprovalDescNetwork": "Requesting to access network or remote content. Verify the target is trusted.", - "ApprovalDescMcpRead": "Requesting to read from an MCP server.", - "ApprovalDescMcpAction": "Requesting to call an MCP server action that may have side effects.", - "ApprovalDescAgent": "Requesting to start or inspect a sub-agent; sub-agents still have their own gating.", - "ApprovalDescUnknown": "Requesting to run an unclassified tool. Review parameters carefully.", + "ApprovalDescSafe": "A safe, read-only operation.", + "ApprovalDescFileWrite": "Modifies a file — confirm the path and content.", + "ApprovalDescShell": "Runs a shell command — review it and the folder first.", + "ApprovalDescNetwork": "Reaches the network or remote content — trust the target first.", + "ApprovalDescMcpRead": "Reads from an MCP server.", + "ApprovalDescMcpAction": "Calls an MCP server action; may have side effects.", + "ApprovalDescAgent": "Starts or inspects a sub-agent, which keeps its own approvals.", + "ApprovalDescUnknown": "Runs an unclassified tool — review its settings carefully.", "ApprovalImpactSafe": "Read-only operation.", "ApprovalImpactFileWrite": "Writes files in the workspace or an approved write scope.", "ApprovalImpactShell": "Executes a Bash command in your workspace.", @@ -1211,10 +1211,10 @@ "SetupGuidedPurposeResearch": "research synthesis", "SetupGuidedPurposeOperations": "operations helper", "SetupGuidedPurposeMixed": "mixed workbench", - "SetupGuidedPurposeAboutCoding": "A Codewhale user who wants a calm, evidence-first coding workbench.", - "SetupGuidedPurposeAboutResearch": "A Codewhale user who wants current, cited research and careful synthesis.", - "SetupGuidedPurposeAboutOperations": "A Codewhale user who wants reliable operational help with clear rollback points.", - "SetupGuidedPurposeAboutMixed": "A Codewhale user who wants a flexible workbench for coding, research, writing, and operations.", + "SetupGuidedPurposeAboutCoding": "A codewhale user who wants a calm, evidence-first coding workbench.", + "SetupGuidedPurposeAboutResearch": "A codewhale user who wants current, cited research and careful synthesis.", + "SetupGuidedPurposeAboutOperations": "A codewhale user who wants reliable operational help with clear rollback points.", + "SetupGuidedPurposeAboutMixed": "A codewhale user who wants a flexible workbench for coding, research, writing, and operations.", "SetupGuidedStyleCoding": "Keep code changes scoped to requested behavior and existing repo patterns.", "SetupGuidedStyleResearch": "Separate live evidence from inference and cite sources for unstable facts.", "SetupGuidedStyleOperations": "Prefer reversible operational steps with dry-runs, status checks, and rollback notes.", @@ -1228,7 +1228,7 @@ "SetupToolsMcpPreviewTitle": "Tools / MCP safe on-ramps", "SetupToolsMcpOnRampText": "Tools, MCP, Skills & Plugins — Safe On-Ramps\n\n/setup only reads local inventory. It never starts MCP servers, installs skills, runs plugins, or executes untrusted commands.\n\nCurrent inventory:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Tools dir: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (shared adapters): {hotbar_result}\n\nPaths (redacted home):\n- MCP config: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nSafe bootstrap (run yourself in a normal terminal or TUI command):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills · /skills install \n- Plugins: /plugin · codewhale setup --plugins\n- Tools dir: codewhale setup --tools\n\nSide-effectful actions always require explicit confirmation. Plugin commands stay distinct from slash commands; the Hotbar plugin source remains deferred until approval gates land.\n\nSee docs/MCP.md and docs/skills/README.md for what still needs manual external setup.", "SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):", - "SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — connected through Codewhale, never a second scheduler:\n- State: {dsh_result}\n- Read-only detection; connect/plan/launch/remove: codewhale integrations dsh status · plan · connect · launch · remove\n- Codewhale writes only $CODEWHALE_HOME/integrations/dsh; it never copies API keys or edits DSH files.", + "SetupToolsMcpDshRow": "DeepSeek Harness (dsh) — connected through codewhale, never a second scheduler:\n- State: {dsh_result}\n- Read-only detection; connect/plan/launch/remove: codewhale integrations dsh status · plan · connect · launch · remove\n- codewhale writes only $CODEWHALE_HOME/integrations/dsh; it never copies API keys or edits DSH files.", "HotbarActionModeOperateName": "Operate mode", "HotbarActionModeOperateDescription": "Put your fleet to work in parallel.", "HomeOperateModeTip": "Operate — put your fleet to work in parallel", @@ -1313,9 +1313,9 @@ "SessionsActionClose": "close", "SessionsScopeSortHeader": "scope and sort · {sort}", "SessionsEmptyTitle": "No saved sessions yet.", - "SessionsEmptyHint": "Send a message to start one; it is saved automatically.", - "SessionsShowingAllWorkspaces": "showing sessions from every workspace", - "SessionsScopedToWorkspace": "scoped to this workspace", + "SessionsEmptyHint": "Send a message to start one — it saves automatically.", + "SessionsShowingAllWorkspaces": "sessions from every workspace", + "SessionsScopedToWorkspace": "this workspace only", "SessionsNewTitlePrompt": "New title: ", "SessionsDeletePrompt": "Delete session? (y/n)", "SessionsConfirmDelete": "Confirm delete (y/n)", @@ -1325,7 +1325,7 @@ "SessionsSortRecent": "recent", "SessionsSortName": "name", "SessionsSortSize": "size", - "SessionsSearchPrompt": "Search: type to filter, Enter to apply", + "SessionsSearchPrompt": "Search: type, Enter to apply", "SessionsDeleteFailed": "Could not delete: {error}", "SessionsDeleted": "Deleted {id}", "SessionsNoSelection": "No session selected", @@ -1359,7 +1359,7 @@ "CtxInspRowSystemPrompt": "system prompt", "CtxInspRowMessages": "messages", "CtxInspRowFree": "free", - "CtxInspFreeTokensDetail": "{free} free tokens remain before the route window is full. Auto-compact threshold: {threshold}%.", + "CtxInspFreeTokensDetail": "{free} free tokens left before the window fills. Auto-compact at {threshold}%.", "CtxInspDrillTitle": "context · {row}", "CtxInspSurfaceTitle": "context", "CtxInspActionSelect": "select", @@ -1403,42 +1403,42 @@ "PickerActionSetKey": "set key", "PickerActionConfigured": "configured", "RouteNoModels": "No models available.", - "RouteNoModelMatch": "No models match \"{query}\" — Backspace to clear.", + "RouteNoModelMatch": "No models match \"{query}\" — Backspace clears.", "ProviderNoMatchesTitle": "No providers match", - "ProviderNoMatchesHint": "Try a different search term or clear to browse.", + "ProviderNoMatchesHint": "Try another search, or clear to browse.", "ProviderNoConfiguredTitle": "No providers configured yet", - "ProviderNoConfiguredHint": "Browse every supported provider or create a custom endpoint.", + "ProviderNoConfiguredHint": "Browse all supported providers, or add a custom endpoint.", "ProviderNoCatalogModels": "No catalog models available.", "ProviderExternalActionRevoke": "revoke external", "ProviderExternalActionChoices": "external access choices", "ProviderExternalActionReuseGrok": "external Grok reuse", - "ProviderExternalHintCodexReview": "After {login}, press Enter to review disabled/read-only/managed access choices.", - "ProviderExternalHintXaiReview": "Press Enter for Codewhale-owned device login; press E to review existing Grok CLI reuse.", - "ProviderExternalHintXaiApiKey": "Or use XAI_API_KEY and re-open this picker.", + "ProviderExternalHintCodexReview": "After {login}, Enter reviews disabled/read-only/managed choices.", + "ProviderExternalHintXaiReview": "Press Enter for codewhale-owned device login; press E to review existing Grok CLI reuse.", + "ProviderExternalHintXaiApiKey": "Or set XAI_API_KEY and re-open this picker.", "XaiAuthChoiceTitle": " xAI authentication ", - "XaiAuthChoiceIntro": "Choose one explicit credential source. Key text is never an OAuth token.", - "XaiAuthChoiceApiKeyOption": "xAI API key — type or paste, then save in the xAI provider slot", - "XaiAuthChoiceDeviceOAuthOption": "Native device OAuth — browser/device-code sign-in with Codewhale-owned storage", + "XaiAuthChoiceIntro": "Pick one credential source. Key text is never an OAuth token.", + "XaiAuthChoiceApiKeyOption": "xAI API key — paste it, then save to the xAI slot", + "XaiAuthChoiceDeviceOAuthOption": "Native device OAuth — browser/device-code sign-in with codewhale-owned storage", "ChatgptAuthChoiceTitle": " ChatGPT / Codex authentication ", - "ChatgptAuthChoiceIntro": "Subscription sign-in bills your ChatGPT plan. The openai API-key route is a different billing owner.", - "ChatgptAuthChoicePkceOption": "Sign in with ChatGPT — browser PKCE, Codewhale-owned tokens, ChatGPT subscription billing", - "ChatgptAuthChoiceImportOption": "Import Codex CLI credentials — explicit read-only consent; Codex CLI remains the owner", - "ProviderExternalHintChatgptReview": "Press Enter to Sign in with ChatGPT; press E to review existing Codex CLI reuse.", + "ChatgptAuthChoiceIntro": "Sign-in bills your ChatGPT plan. The openai API-key route bills separately.", + "ChatgptAuthChoicePkceOption": "Sign in with ChatGPT — browser PKCE, codewhale-owned tokens, ChatGPT subscription billing", + "ChatgptAuthChoiceImportOption": "Import Codex CLI credentials — read-only, with your consent; Codex CLI stays the owner", + "ProviderExternalHintChatgptReview": "Enter signs in with ChatGPT; E reviews existing Codex CLI reuse.", "ProviderExternalActionReuseCodex": "external Codex reuse", "ProviderExternalDetailScope": "External: access={access} | provider={provider} | source={source} | version={version} | {state}", "ProviderExternalDormant": "dormant", "ProviderExternalOwnerPath": "Owner/path: {owner} | {path}", "ProviderExternalPinnedPathWarning": "Warning: ambient {owner} credential path changed; consent remains pinned to {path}.", - "ToolProjectionWarning": "Warning: {provider} omitted incompatible tools for this request: {tools}", + "ToolProjectionWarning": "Warning: {provider} dropped incompatible tools for this request: {tools}", "ProviderExternalSemanticsRevoke": "{semantics} | revoke: {revoke}", "ProviderExternalRevoke": "revoke: {revoke}", "ProviderExternalChoiceTitle": " External credential access · {provider} ", "ProviderExternalActionChoose": "choose", - "ProviderExternalChoiceIntro": "Choose what Codewhale may do with credentials owned by another CLI.", + "ProviderExternalChoiceIntro": "Choose what codewhale may do with credentials owned by another CLI.", "ProviderExternalDisabledLabel": "Disabled (default)", "ProviderExternalDisabledDetail": "no probing, reads, refresh, network, or writes", "ProviderExternalReadOnlyLabel": "Use external CLI credentials (read-only)", - "ProviderExternalReadOnlyDetail": "one exact file; explicit confirmation follows", + "ProviderExternalReadOnlyDetail": "one exact file, confirmed explicitly", "ProviderExternalReadOnlySemantics": "read this exact file; no refresh, identity-provider or discovery requests, external-file writes, or rewrites; normal requests to the selected provider may use its token", "ProviderExternalManagedLabel": "Managed (unavailable)", "ProviderExternalManagedDetail": "no reviewed schema-safe preservation adapter", @@ -1447,12 +1447,12 @@ "ProviderExternalOwnerLabel": "Owning CLI", "ProviderExternalExactPathLabel": "Exact resolved path", "ProviderExternalSemanticsLabel": "Semantics", - "ProviderExternalRejectUnsafe": "Codewhale will reject symlinks, reparse points, and non-regular files.", + "ProviderExternalRejectUnsafe": "codewhale rejects symlinks, reparse points, and non-regular files.", "ProviderExternalRevokeLabel": "Revoke", "ProviderExternalRouteLabel": "Route", - "ProviderExternalCustodyLine": "Custody: local device only — Codewhale stores this consent record, not the credential; no account or cloud vault is used.", - "ProviderExternalBillingLine": "Credential & billing owner: your {owner} account; usage is billed by that account.", - "ProviderExternalRevokeScope": "Revoking clears only Codewhale's consent record on this device; the {owner} file is never read, modified, or deleted.", + "ProviderExternalCustodyLine": "Custody: local device only — codewhale stores this consent record, not the credential; no account or cloud vault is used.", + "ProviderExternalBillingLine": "Credential and billing owner: your {owner} account.", + "ProviderExternalRevokeScope": "Revoking clears only codewhale's consent record on this device; the {owner} file is never read, modified, or deleted.", "ProviderExternalOwnerOnly": "Owner: {owner}", "ProviderExternalPinnedPathChanged": "Warning: ambient {owner} credential path changed; consent stays pinned to the granted path.", "ProviderExternalRevokeConfirmTitle": " Revoke external credential access? ", @@ -1469,7 +1469,7 @@ "FleetRosterTabSetup": "setup", "FleetRosterWorkers": "workers", "FleetRosterMembersCount": "{count} members", - "FleetRosterOperatorFirst": "Coordinator leads · session model runs this fleet", + "FleetRosterOperatorFirst": "Coordinator leads · your session model runs this fleet", "FleetRosterOperatorRow": "Coordinator · leader", "FleetRosterShadowBadgeProjectOverride": "saved in this project", "FleetRosterShadowBadgePersonalIgnored": "saved copy ignored", @@ -1478,7 +1478,7 @@ "FleetRosterLayersLabel": "Saved for", "FleetRosterLayerWins": "active", "FleetRosterLayerIgnored": "ignored copy", - "FleetReadyNotice": "fleet is ready · /fleet opens roles · /fleet setup customizes members' models", + "FleetReadyNotice": "fleet is ready · /fleet shows roles · /fleet setup tunes models", "FleetProfileIdentityVerifyFailed": "Could not verify existing profile identities ({error}); fix the named file before saving.", "FleetProfileIdConflict": "Profile id `{id}` is already used by {path}; redraft with a different role or remove the old file first.", "FleetProfileProviderUnconfigured": "Profile pins provider `{provider}`, which has no configured credentials ({env}); set it up in /provider before saving.", @@ -1489,13 +1489,13 @@ "FleetModelRemoved": "Removed {route} from the fleet `{fleet}`", "FleetModelRemovedRoles": "Removed {route} ({roles}) from the fleet `{fleet}`", "FleetModelUnchanged": "{route} stays in the fleet `{fleet}`: {reason}", - "FleetModelReasonOperatorRoute": "this is your current model (the fleet's operator route); switch models or use /fleet save to change it", + "FleetModelReasonOperatorRoute": "this is your current model (the operator route); switch models or /fleet save to change it", "FleetModelReasonAlreadyPresent": "already in the fleet", "FleetModelErrorNeedsRoute": "a fleet model needs both a provider id and a model id", - "FleetModelErrorNoSelection": "no fleet is selected; your fleet is the session model only", + "FleetModelErrorNoSelection": "no fleet selected; using your session model only", "FleetModelErrorOperatorRoute": "{route} is the operator route of the fleet `{fleet}`; change it with /fleet save, not remove", "FleetModelErrorNotInFleet": "{route} is not in the fleet `{fleet}`", - "FleetModelsEmpty": "Your fleet is the session model only. Add one: /fleet add [role…] (or ⇧F on a row in /model).", + "FleetModelsEmpty": "Your fleet is the session model only — add one: /fleet add [role…] (or ⇧F on a /model row).", "FleetModelsHeader": "Your fleet `{fleet}` ({count} models)", "FleetModelsBroken": "Your selected fleet could not be loaded: {error}. Fix the file or pick another with /fleet fleets.", "FleetModelsFooter": "Add: /fleet add [role…] · Remove: /fleet remove ", @@ -1503,20 +1503,20 @@ "FleetModelsFactContext": "{context}k ctx", "FleetModelsFactTools": "tools", "FleetAddUsage": "Usage: /fleet add [role…] — e.g. /fleet add openrouter z-ai/glm-5.3-flash explore", - "FleetAddProviderUnconfigured": "`{provider}` is not a configured provider. Configure it in ~/.codewhale/config.toml or switch to it with /provider before adding it to the fleet.", - "FleetAddModelNotServed": "{provider} does not serve `{model}` in the current catalog; run /models to see what it serves, or /fleet add with the exact id it lists.", + "FleetAddProviderUnconfigured": "`{provider}` is not a configured provider yet. Add it in ~/.codewhale/config.toml or switch with /provider, then retry.", + "FleetAddModelNotServed": "{provider} does not serve `{model}` right now; run /models to see what it serves, or retry with the exact id it lists.", "FleetAddFailed": "Could not add to the fleet: {error}", "FleetRemoveUsage": "Usage: /fleet remove ", "FleetRemoveFailed": "Could not remove from the fleet: {error}", "FleetToggleFailed": "Could not update the fleet: {error}", "FleetDestStepTitle": "Where should this profile live?", - "FleetDestStepSubtitle": "Nothing is written until you confirm on the last step.", + "FleetDestStepSubtitle": "Nothing is saved until the last step.", "FleetDestProjectLabel": "This project", "FleetDestPersonalLabel": "Personal", "FleetDestProjectSummary": "Only this project", "FleetDestPersonalSummary": "Available in every project", - "FleetDestProjectDescription": "Saved inside this project ({workspace}). It applies here only, and it takes precedence over a Personal profile with the same ID.", - "FleetDestPersonalDescription": "Saved in your Codewhale home. It applies in every project — except where a project has its own profile with the same ID, which takes precedence there.", + "FleetDestProjectDescription": "Saved inside this project ({workspace}) for this project only; it beats a Personal profile with the same ID here.", + "FleetDestPersonalDescription": "Saved in your codewhale home for every project — unless a project profile with the same ID wins there.", "FleetDestPathLine": "File: {path}", "FleetDestUnavailable": "Not available: {reason}", "FleetDestReasonNoProjectConfig": "project profiles are disabled for this session (--no-project-config)", @@ -1537,7 +1537,7 @@ "FleetActionBack": "Back", "FleetReviewSavesTo": "Saves to", "FleetModelRowBlockedNotice": "Not selectable: {reason}. Configure it in /provider or pick another row.", - "FleetDestProjectDisabledSave": "Project profiles are disabled for this session (--no-project-config); nothing was saved. Choose Personal or restart without the flag.", + "FleetDestProjectDisabledSave": "Project profiles are off this session (--no-project-config); nothing was saved. Choose Personal or restart without the flag.", "WorkflowStatusWaiting": "waiting", "WorkflowStatusDegraded": "degraded", "WorkflowDebrief": "debrief: {done}/{total} settled · {failed} failed · {cancelled} cancelled · {elapsed}", @@ -1621,16 +1621,16 @@ "SettingSubjectModelAndThinking": "Model and thinking", "SettingSubjectProvider": "Provider", "SettingSubjectPermissions": "Permissions", - "ThinkingControlledByAutoRouting": "Thinking is controlled by automatic model routing; choose a fixed model first.", + "ThinkingControlledByAutoRouting": "Auto routing controls thinking; pick a fixed model first.", "SavedAsStartupDefault": "saved as startup default", - "ModeAlreadyActiveSavedAsDefault": "Already in {mode} mode — saved as startup default.", + "ModeAlreadyActiveSavedAsDefault": "Already in {mode} — saved as startup default.", "StartupDefaultNotSaved": "{setting} couldn't be saved: {error}", "StartupDefaultSubjectMode": "startup mode", "StartupDefaultSubjectThinking": "thinking level", "StartupDefaultSubjectModel": "model", "StartupDefaultSubjectAll": "startup defaults", "SessionsRailTitle": "Sessions", - "SessionsRailEmpty": "No sessions in this workspace yet", + "SessionsRailEmpty": "No sessions here yet", "SessionsRailBrowseAll": "Browse all sessions", "SessionsRailShowingCount": "{shown} of {total} — browse all", "SessionsRailUnavailable": "Sessions unavailable: {error}", @@ -1768,7 +1768,7 @@ "StatusToolRawPressure": "{count} raw over cap (~{chars} chars) adding context pressure", "StatusToolCompactReceipts": "{count} compact receipt(s)", "StatusToolArtifacts": "{count} artifact(s), {bytes} stored", - "StatusToolNone": "no large outputs tracked", + "StatusToolNone": "no large outputs", "StatusSafetyReadOnlyUnenforced": "no OS sandbox on this platform (read-only requested, not enforced), network off", "StatusSafetyReadOnly": "sandbox read-only, network off", "StatusSafetyWorkspaceWriteUnenforcedNetworkOn": "no OS sandbox on this platform (workspace-write requested, not enforced), network on", @@ -1792,18 +1792,18 @@ "PermissionsPostureAuto": "Auto-Review: never opens a prompt. A deterministic policy allows proven-safe calls and hard-blocks publish-like or destructive background work; calls it cannot prove safe go to a one-shot model guardian that allows or denies with a stated reason (high or critical risk never auto-runs; a failed review denies, fail closed). Holds that require a person are denied, not hidden. Each such decision is written to the transcript as a note and to the audit log.", "PermissionsPostureBypass": "Full Access: ordinary tool calls run without prompts. Non-bypassable registered holds auto-approve. Repository-law and managed-policy holds fail closed as hard blocks instead of prompting.", "PermissionsPostureNever": "never: only tools considered safe/read-only run; everything else is blocked without a prompt.", - "PermissionsReceiptsNote": "Decisions made without a prompt (Auto-Review guardian verdicts, blocks, and holds) appear as transcript notes and in the audit log at {audit_path}. Full Access is chosen deliberately with Shift+Tab or /config, never by a rule.", - "AgentFocusOpened": "Focused on {agent}. Your messages now go to this worker; Esc returns to the main conversation.", - "AgentFocusClosed": "Back to the main conversation.", + "PermissionsReceiptsNote": "Promptless decisions (verdicts, blocks, holds) appear as transcript notes and in the audit log at {audit_path}. Full Access is always your explicit choice (Shift+Tab or /config).", + "AgentFocusOpened": "Talking to {agent} now — Esc returns to the main thread.", + "AgentFocusClosed": "Back to the main thread.", "AgentFocusBanner": "{agent} · {status}", "AgentFocusComposerChip": "→ {agent}", "AgentFocusPlaceholder": "Message {agent} · Esc returns to main", - "AgentFocusNoTranscript": "No transcript captured yet for {agent}. Messages appear here as the worker exchanges them.", - "AgentFocusOmitted": "Earlier messages ({count}) are omitted from the in-memory transcript.", - "AgentFocusFollowUpDelivered": "Queued for {agent}: it reads the message at its next round.", + "AgentFocusNoTranscript": "Nothing from {agent} yet — messages land here as they arrive.", + "AgentFocusOmitted": "Earlier messages ({count}) aren't in memory.", + "AgentFocusFollowUpDelivered": "Queued for {agent} — it reads it next round.", "AgentFocusFollowUpQueued": "Queued for {agent}", - "AgentFocusFollowUpContinued": "{agent} had finished; continued on a new fork ({target}). This view now follows the fork.", - "AgentFocusFollowUpFailed": "Could not deliver to {agent}: {reason}", + "AgentFocusFollowUpContinued": "{agent} had finished — continuing on fork ({target}). This view follows the fork.", + "AgentFocusFollowUpFailed": "Couldn't reach {agent}: {reason}", "FooterHintForAgents": "for agents", "FooterHintToManage": "to manage", "AgentRailQueuedCount": "{count} queued", @@ -1815,25 +1815,25 @@ "AgentFocusPostureShellFull": "shell", "AgentFocusPostureShellReadOnly": "read-only shell", "AgentFocusPostureShellNone": "no shell", - "GoalReceiptSet": "Goal set: \"{objective}\" · /goal shows progress · /goal pause or /goal clear stops it", - "GoalReceiptSetOperate": "◆ goal set · Operate keeps working until it is verified · /goal to edit", - "GoalControlAccepted": "Goal control saved; applying at the next safe boundary.", - "GoalControlRuntimeUnavailable": "Goal control is saved, but the runtime is unavailable. It will be restored after restart.", - "GoalStatusIdleHint": "not running now — send a message or /goal resume to continue", + "GoalReceiptSet": "Goal set: \"{objective}\" · /goal tracks it · /goal pause or /goal clear stops it", + "GoalReceiptSetOperate": "◆ goal set · Operate works till it's verified · /goal edits it", + "GoalControlAccepted": "Goal control saved — applies at the next safe point.", + "GoalControlRuntimeUnavailable": "Goal control saved, but the runtime is down. It returns after restart.", + "GoalStatusIdleHint": "paused — send a message or /goal resume", "CmdAutoDescription": "Work with Auto-Review — skip a goal or workflow", "AutoReceiptOn": "Auto-Review on. /goal keeps one objective; /workflow runs a script.", "AutoReceiptPlanNote": "Plan stays Read Only until you switch to Work or Operate.", - "GoalContinuationWaiting": "Goal active · next turn in {delay} · Esc, Ctrl+C, or /goal pause stops the pending continuation", - "GoalContinuationReady": "Goal continuation ready; queued controls run before the next turn.", - "GoalContinuationStopped": "Pending goal continuation stopped; the goal remains active.", + "GoalContinuationWaiting": "Goal active · next turn in {delay} · Esc, Ctrl+C, or /goal pause stops it", + "GoalContinuationReady": "Goal ready — queued controls run before the next turn.", + "GoalContinuationStopped": "Pending continuation stopped; the goal stays active.", "McpCapabilitiesAdvertised": "Advertised capabilities: {capabilities}", "McpCapabilitiesLegacyFallback": "Advertised capabilities: not provided; using legacy discovery fallback", "McpCapabilitiesNotObserved": "Advertised capabilities: not observed because the server is not connected", "PickerActionTemplates": "templates", "PickerActionTestConnection": "test connection", "ProviderTemplatesTitle": "Setup templates", - "ProviderTemplatesIntro": "First-class routes keep their existing key-only setup. Compatible hosts fill Base URL and model. Unpublished rows have no published URL.", - "ProviderTemplateUnpublished": "No published OpenAI-compatible URL in this repository, so this is not a fillable preset.", + "ProviderTemplatesIntro": "First-class routes keep key-only setup. Compatible hosts fill in Base URL and model. Unpublished rows have no URL.", + "ProviderTemplateUnpublished": "No published OpenAI-compatible URL here, so this row isn't a fillable preset.", "ProviderTemplateDocs": "Docs: {url}", "ProviderTemplateCredentials": "Keys: {url}", "ProviderTemplateKindKeyOnly": "key-only", @@ -1841,24 +1841,24 @@ "ProviderTemplateKindUnpublished": "unpublished", "ProviderTemplateBaseUrl": "Base URL: {url}", "ProviderTemplateModel": "Model: {model}", - "ProviderTemplateGuidanceOpencodeZen": "Create or copy an OpenCode Zen API key from OpenCode Zen.", - "ProviderTemplateGuidanceOpencodeGo": "Create or copy an OpenCode Go subscription key from OpenCode Zen.", - "ProviderTemplateGuidanceSenseNova": "OpenAI-compatible SenseTime SenseNova host. Store an env var name, not a raw key.", - "ProviderTemplateGuidanceAgnes": "Agnes has no published OpenAI-compatible URL in this repository, so it has no fillable preset.", + "ProviderTemplateGuidanceOpencodeZen": "Grab an OpenCode Zen API key from OpenCode Zen.", + "ProviderTemplateGuidanceOpencodeGo": "Grab an OpenCode Go subscription key from OpenCode Zen.", + "ProviderTemplateGuidanceSenseNova": "SenseTime SenseNova host (OpenAI-compatible). Store an env var name, not a raw key.", + "ProviderTemplateGuidanceAgnes": "Agnes has no published OpenAI-compatible URL, so no fillable preset.", "ProviderCustomFormBaseUrl": "Base URL", "ProviderCustomFormModel": "Default model", "ProviderCustomFormHint": "OpenAI-compatible endpoint. Store an env var name, not a raw key. OpenCode Zen/Go are first-class rows. SenseNova: S. Agnes has no published URL.", - "ConfigLabelProviderTemplates": "Beginner provider templates", + "ConfigLabelProviderTemplates": "Provider templates", "ConfigActionOpenProviderTemplates": "Enter opens template list", "ConfigHintProviderTemplates": "P in /provider; C-t tests /models without treating 2xx as model-ready", - "ProviderConnectionChecked": "Connection checked (/models returned 2xx). Model availability is not checked.", - "ProviderConnectionCheckedPickModel": "Connection checked (/models returned 2xx). Pick a default model; model availability is not checked.", + "ProviderConnectionChecked": "Connection ok (/models returned 2xx); model availability still unchecked.", + "ProviderConnectionCheckedPickModel": "Connection ok (/models returned 2xx). Pick a default model — availability still unchecked.", "ProviderTestConnectionNeedKey": "No API key saved for {provider}. Add one first, then press T to test.", "ProviderTestConnectionFailed": "Could not reach {provider}: {error}", "ProviderTestConnectionNoEndpoint": "{provider} exposes no /models endpoint; reachability unprobed.", - "ProviderTemplateOpened": "Provider template '{id}' opened. Enter an API key only.", - "ProviderTemplateUnknown": "Unknown provider template '{id}'.", - "ProviderTemplateOpenedEnvOnly": "Built-in template '{id}' opened. Enter the API key env var name, then save. Do not paste a raw key.", + "ProviderTemplateOpened": "Template '{id}' opened — API key only.", + "ProviderTemplateUnknown": "No template named '{id}'.", + "ProviderTemplateOpenedEnvOnly": "Template '{id}' opened — enter the key's env var name and save. Never paste the raw key.", "OperateBoardHeader": "Operate {id} [{status}] pace={pace} writers={writers}", "OperateBoardBurnObserved": "burn ${actual}/hr observed vs ${target}/hr target", "OperateBoardBurnNoCap": "burn No cap", @@ -1916,7 +1916,7 @@ "ConfigLaneUnavailable": "unavailable: {error}", "ConfigSourceEnvironment": "environment override ({name})", "ConfigSourceTerminal": "terminal override ({name})", - "ConfigDescriptionDefault": "Enter changes the value · Esc closes. The badge shows the scope.", + "ConfigDescriptionDefault": "Enter changes it · Esc closes · the badge shows scope", "ConfigValueOn": "On", "ConfigValueOff": "Off", "ConfigValueProviderDefault": "Provider default", @@ -1935,19 +1935,19 @@ "ConfigChoiceRailAgents": "Agents", "ConfigChoiceRailContext": "Context", "ConfigChoiceRailPinned": "Pinned", - "ConfigChoiceStatusCw": "Codewhale mark", + "ConfigChoiceStatusCw": "codewhale mark", "ConfigChoiceStatusWhale": "Animated whale", "ConfigChoiceStatusDots": "Animated dots", "ConfigChoiceDiffFull": "Full diff", "ConfigChoiceDiffSummary": "Summary", - "ConfigChoiceDetailAsk": "Ask before tools that can make consequential changes.", - "ConfigChoiceDetailAutoReview": "Review tool risk automatically and ask when a decision needs you.", - "ConfigChoiceDetailUseTuiDefault": "Remove the root config override and use the saved TUI permission choice.", - "ConfigChoiceDetailFullAccess": "Run tools without approval prompts; workspace rules still apply.", + "ConfigChoiceDetailAsk": "Ask before tools that change things.", + "ConfigChoiceDetailAutoReview": "Auto-check tool risk; ask when a call needs you.", + "ConfigChoiceDetailUseTuiDefault": "Drop the raw config override; use the saved choice.", + "ConfigChoiceDetailFullAccess": "Run tools without prompts; workspace rules still apply.", "ConfigChoiceDetailNever": "Block every tool that requires approval.", - "ConfigChoiceDetailModeAgent": "Start ready to collaborate and use tools.", + "ConfigChoiceDetailModeAgent": "Start ready to work with tools.", "ConfigChoiceDetailModePlan": "Start in a read-only planning workspace.", - "ConfigChoiceDetailModeOperate": "Operate turns your prompt into a goal and works it in parallel: background workers for separable streams, verified before it stops.", + "ConfigChoiceDetailModeOperate": "Operate turns your prompt into a goal and works it in parallel, verified before it stops.", "ConfigChoiceDetailPlacementTop": "Show Tasks, To-do, and Workers above the transcript.", "ConfigChoiceDetailPlacementLeft": "Show Tasks, To-do, and Workers in a left sidebar when the terminal is wide enough.", "ConfigChoiceDetailPlacementRight": "Show Tasks, To-do, and Workers in a right sidebar when the terminal is wide enough.", @@ -1956,19 +1956,19 @@ "ConfigChoiceDetailRailAgents": "Rail shows sub-agents and fan-out state.", "ConfigChoiceDetailRailContext": "Rail shows workspace, token, and cost context.", "ConfigChoiceDetailRailPinned": "Rail shows the pinned goal and checklist summary.", - "ConfigChoiceDetailLowMotionOn": "Stops live-state movement without changing model output.", - "ConfigChoiceDetailLowMotionOff": "Allows motion selected by the other appearance settings.", - "ConfigChoiceDetailFancyOn": "Animates truthful tool, status, and ocean live state.", - "ConfigChoiceDetailFancyOff": "Keeps live-state markers and the ocean treatment static.", - "ConfigChoiceDetailShowThinkingOn": "Show model reasoning blocks in the transcript.", - "ConfigChoiceDetailShowThinkingOff": "Keep model reasoning hidden; answers and tools remain visible.", - "ConfigChoiceDetailThinkingHighlightOn": "Fill the model reasoning background.", - "ConfigChoiceDetailThinkingHighlightOff": "Keep the dashed reasoning rail and italic text without a filled background.", - "ConfigChoiceDetailOceanDeepsea": "Use one continuous ocean color field.", - "ConfigChoiceDetailOceanFlat": "Use a single flat background color.", - "ConfigHintModel": "live route model for this session; Enter opens /model", - "ConfigHintFastModel": "used by Auto routing and agent model_strength=faster when this provider has a known sibling", - "ConfigHintProvider": "live route provider for this session; Enter opens /provider (credential, model, and endpoint switch together)", + "ConfigChoiceDetailLowMotionOn": "Calms live motion; model output is unchanged.", + "ConfigChoiceDetailLowMotionOff": "Lets appearance settings control motion.", + "ConfigChoiceDetailFancyOn": "Animates tool, status, and ocean state.", + "ConfigChoiceDetailFancyOff": "Keeps markers and the ocean still.", + "ConfigChoiceDetailShowThinkingOn": "Show reasoning in the transcript.", + "ConfigChoiceDetailShowThinkingOff": "Hide reasoning; answers and tools stay visible.", + "ConfigChoiceDetailThinkingHighlightOn": "Fill reasoning's background.", + "ConfigChoiceDetailThinkingHighlightOff": "Keep the dashed rail and italics, no fill.", + "ConfigChoiceDetailOceanDeepsea": "One continuous ocean color field.", + "ConfigChoiceDetailOceanFlat": "One flat background color.", + "ConfigHintModel": "this session's model; Enter opens /model", + "ConfigHintFastModel": "used by Auto routing and model_strength=faster when this provider has a known sibling", + "ConfigHintProvider": "this session's provider; Enter opens /provider (credential, model, endpoint switch together)", "ConfigHintApprovalMode": "this session only: Ask | Auto-Review | Full Access", "ConfigHintPermissionPosture": "default for new sessions: Ask | Auto-Review | Full Access", "ConfigHintApprovalPolicy": "new sessions: Ask | Auto-Review | Full Access; choosing Full Access releases the raw config override", @@ -1978,47 +1978,47 @@ "ConfigHintComposerMultilineMode": "off: Enter sends, Shift+Enter adds a line; on: Enter adds a line, Shift+Enter sends", "ConfigHintBooleanValues": "on/off, true/false, yes/no, 1/0", "ConfigHintDensity": "compact | comfortable | spacious", - "ConfigHintInlineDiffs": "full | summary | off; exact change remains in Alt/Option+V details", + "ConfigHintInlineDiffs": "full | summary | off; full change stays in Alt/Option+V", "ConfigHintToolCollapse": "compact | expanded | calm", "ConfigHintBackgroundColor": "#RRGGBB | default", - "ConfigHintWorkSurfacePlacement": "top | left | right | off · side rails require Ocean mode and at least 72 columns", - "ConfigHintRailPanel": "tasks | agents | context | pinned · which panel the rail shows", - "ConfigHintWorkSurfaceTopHeight": "5..=16 rows · also adjustable by dragging the divider", - "ConfigHintWorkSurfaceSideWidth": "26..=80 columns · also adjustable by dragging the divider", - "ConfigHintBaseUrl": "read-only route receipt for the live endpoint · change provider, credential, and endpoint together with /provider", - "ConfigHintContextWindow": "max context length / context size limit in tokens · set `[providers.] context_window` in config.toml, e.g. 1048576 for a 1M route; (not set) resolves it automatically", - "ConfigHintEffectiveContextWindow": "resolved max context length / window size limit in tokens and where the value came from; drives compaction, pressure, and preflight budgets", + "ConfigHintWorkSurfacePlacement": "top | left | right | off · side rails need Ocean mode and 72+ columns", + "ConfigHintRailPanel": "tasks | agents | context | pinned", + "ConfigHintWorkSurfaceTopHeight": "5..=16 rows · or drag the divider", + "ConfigHintWorkSurfaceSideWidth": "26..=80 columns · or drag the divider", + "ConfigHintBaseUrl": "live endpoint receipt (read-only) · switch all three with /provider", + "ConfigHintContextWindow": "max context length / context size limit in tokens · set `[providers.] context_window` in config.toml (e.g. 1048576); unset resolves automatically", + "ConfigHintEffectiveContextWindow": "resolved max context length / context size limit in tokens, its source, and what it drives (compaction, pressure, preflight)", "ConfigHintCostCurrency": "usd | cny", - "ConfigHintCalmMode": "quietens transcript chrome and tool detail; independent of live motion", - "ConfigHintLowMotion": "on overrides live-state motion; model output is unchanged", - "ConfigHintFancyAnimations": "on animates truthful tool, status, and ocean live state", - "ConfigHintOceanTreatment": "deepsea | flat (appearance; independent of motion)", - "ConfigHintShowThinking": "show or hide model reasoning in chat; task lists stay concise", - "ConfigHintThinkingDefaultExpanded": "expand model reasoning by default; Space still toggles each block", + "ConfigHintCalmMode": "quiets the transcript; motion settings stay separate", + "ConfigHintLowMotion": "on calms live motion; model output is unchanged", + "ConfigHintFancyAnimations": "on animates tool, status, and ocean state", + "ConfigHintOceanTreatment": "deepsea | flat (look only; motion is separate)", + "ConfigHintShowThinking": "show or hide reasoning; task lists stay short", + "ConfigHintThinkingDefaultExpanded": "expand reasoning by default; Space still toggles", "ConfigHintThinkingPreviewLines": "collapsed completed-thought preview rows (default 2; 0=header-only; 10=older dump)", - "ConfigHintHelpExpandGroups": "start Help/shortcuts with every group expanded; default folds the long tail", - "ConfigHintPinLastPrompt": "pin the last user prompt at the top of the transcript when it scrolls off", - "ConfigHintThinkingHighlight": "fill the model reasoning background; the dashed rail remains visible when off", - "ConfigHintSynchronizedOutput": "auto | on | off; terminal redraw pacing, not model speed", + "ConfigHintHelpExpandGroups": "open Help with every group expanded; default folds the tail", + "ConfigHintPinLastPrompt": "keep your last prompt pinned atop the transcript", + "ConfigHintThinkingHighlight": "fill reasoning's background; the dashed rail stays when off", + "ConfigHintSynchronizedOutput": "auto | on | off; redraw pacing, not model speed", "ConfigHintDefaultMode": "act (agent) | plan | operate", "ConfigHintMaxHistory": "integer (0 allowed)", - "ConfigHintAutoCompactThreshold": "10..=100 · compaction threshold: percent of the usable context length at which auto-compaction fires", - "ConfigHintDefaultModel": "DeepSeek-only legacy fallback; other providers use their provider-scoped model above", - "ConfigHintReasoningEffort": "Per-model thinking ladder from the active route. default clears the saved value and uses that model's official default. Always-thinking models omit off.", + "ConfigHintAutoCompactThreshold": "10..=100 · context percent that triggers auto-compaction", + "ConfigHintDefaultModel": "DeepSeek-only legacy fallback; others use their model above", + "ConfigHintReasoningEffort": "Thinking ladder for the active route. default restores the model's own default. Always-thinking models skip off.", "ConfigHintMcpOpen": "open the MCP manager · Connect / Reconnect / Re-auth / Diagnose", "ConfigHintMcpReconnect": "reconnect MCP · /mcp reload", "ConfigHintMcpDiagnose": "diagnose MCP · /mcp validate", "ConfigHintPluginsOpen": "open plugins · trust, enable, or diagnose", "ConfigHintMcpConfigPath": "path to mcp.json", - "ConfigHintFleetMaxSpawnDepth": "0 blocks child agents; 3 default (same axis as sub-agents); capped at 8", - "ConfigHintFeatureSubagents": "read-only feature flag state; /fleet setup is the user-facing path", - "ConfigHintFeatureWebSearch": "read-only feature flag state for web search tools", - "ConfigHintFeatureApplyPatch": "read-only feature flag state for patch editing tools", - "ConfigHintFeatureMcp": "read-only feature flag state for MCP tools", - "ConfigHintFeatureExecPolicy": "read-only feature flag state for execution policy tools", + "ConfigHintFleetMaxSpawnDepth": "0 blocks child agents; default 3; max 8", + "ConfigHintFeatureSubagents": "read-only flag; use /fleet setup", + "ConfigHintFeatureWebSearch": "read-only flag for web search tools", + "ConfigHintFeatureApplyPatch": "read-only flag for patch editing tools", + "ConfigHintFeatureMcp": "read-only flag for MCP tools", + "ConfigHintFeatureExecPolicy": "read-only flag for execution policy tools", "ConfigHintFeatureVisionModel": "beta feature flag for vision/model image support", - "ConfigHintGoalCommand": "/goal sets objectives, budgets, and Work-context status", - "ConfigHintWorkflow": "/workflow runs scripted operations with fan-out/fan-in run cards", + "ConfigHintGoalCommand": "/goal tracks objectives, budgets, and status", + "ConfigHintWorkflow": "/workflow runs scripted ops with fan-out", "LaunchMenuNewWorktree": "New worktree", "LaunchMenuResume": "Resume session", "LaunchMenuQuit": "Quit", diff --git a/crates/tui/src/commands/groups/core/core.rs b/crates/tui/src/commands/groups/core/core.rs index e4a0a3bff6..9ddec55472 100644 --- a/crates/tui/src/commands/groups/core/core.rs +++ b/crates/tui/src/commands/groups/core/core.rs @@ -873,7 +873,7 @@ mod tests { let result = help(&mut app, Some("links")); let msg = result.message.expect("help topic should return message"); assert!(msg.contains("links")); - assert!(msg.contains("Show Codewhale, community, and provider links")); + assert!(msg.contains("Show codewhale, community, and provider links")); assert!(msg.contains("Usage: /links")); assert!(msg.contains("Aliases: dashboard, api")); } @@ -1597,7 +1597,7 @@ mod tests { assert_eq!(app.view_stack.top_kind(), Some(ModalKind::SubAgents)); assert_eq!( app.status_message, - Some("Fetching current-session sub-agents...".to_string()) + Some("Finding this session's sub-agents...".to_string()) ); } diff --git a/crates/tui/src/commands/groups/plugins/tests.rs b/crates/tui/src/commands/groups/plugins/tests.rs index 84419781a3..893631d93f 100644 --- a/crates/tui/src/commands/groups/plugins/tests.rs +++ b/crates/tui/src/commands/groups/plugins/tests.rs @@ -139,7 +139,7 @@ fn list_show_validate_are_read_only_and_label_legacy_tools() { let list = plugins(&mut app, Some("list")).message.unwrap(); assert!(list.contains("Plugin bundles (1)")); assert!(list.contains("disabled")); - assert!(list.contains("Legacy executable plugin tools (1)")); + assert!(list.contains("Legacy plugin tools (1)")); } #[test] diff --git a/crates/tui/src/commands/groups/utility/mcp.rs b/crates/tui/src/commands/groups/utility/mcp.rs index 0c9a37372e..418f7bdd95 100644 --- a/crates/tui/src/commands/groups/utility/mcp.rs +++ b/crates/tui/src/commands/groups/utility/mcp.rs @@ -238,8 +238,7 @@ fn mcp_unknown_id(presentation: &mut dyn CommandPresentationContext) -> String { &[("recommendations_command", "/mcp recommendations")], ) .unwrap_or_else(|_| { - "Unknown recommended MCP ID. Run /mcp recommendations to inspect the curated list." - .to_string() + "Unknown MCP suggestion. Run /mcp recommendations to see the list.".to_string() }) } @@ -247,7 +246,7 @@ fn recommended_mcp_text(presentation: &mut dyn CommandPresentationContext) -> St let heading = presentation .translate("mcp_recommendations_heading", &[]) .unwrap_or_else(|_| { - "Suggested Codewhale plugins (MCP components; nothing is installed automatically)" + "Suggested codewhale plugins (MCP components; nothing installs automatically)" .to_string() }); let safety = presentation @@ -255,7 +254,7 @@ fn recommended_mcp_text(presentation: &mut dyn CommandPresentationContext) -> St "mcp_recommendations_safety", &[("restart_command", "/mcp restart")], ) - .unwrap_or_else(|_| "Viewing this list adds or enables nothing.".to_string()); + .unwrap_or_else(|_| "Looking adds nothing.".to_string()); let github = presentation .translate( "mcp_recommendation_github", @@ -281,7 +280,7 @@ fn recommended_mcp_text(presentation: &mut dyn CommandPresentationContext) -> St ], ) .unwrap_or_else(|_| { - format!("• chrome-devtools — official Chrome DevTools MCP via pinned npm package\n package: {CHROME_DEVTOOLS_MCP_PACKAGE}") + format!("• chrome-devtools — official Chrome DevTools MCP (pinned npm package)\n package: {CHROME_DEVTOOLS_MCP_PACKAGE}") }); let playwright = presentation .translate( @@ -295,7 +294,7 @@ fn recommended_mcp_text(presentation: &mut dyn CommandPresentationContext) -> St ], ) .unwrap_or_else(|_| { - format!("• playwright — Microsoft's official Playwright MCP via pinned npm package\n package: {PLAYWRIGHT_MCP_PACKAGE}") + format!("• playwright — Microsoft's official Playwright MCP (pinned npm package)\n package: {PLAYWRIGHT_MCP_PACKAGE}") }); let cua = presentation .translate( @@ -396,7 +395,7 @@ mod tests { "Unknown recommended MCP ID. Run {recommendations_command} to inspect the curated list.".to_string() } "mcp_recommendations_heading" => { - "Suggested Codewhale plugins (MCP components; nothing is installed automatically)" + "Suggested codewhale plugins (MCP components; nothing installs automatically)" .to_string() } "mcp_recommendations_safety" => { @@ -459,7 +458,7 @@ mod tests { let recommended = mcp(&mut FakePresentation, Some("recommendations")) .message .expect("recommendations text"); - assert!(recommended.contains("nothing is installed automatically")); + assert!(recommended.contains("nothing installs automatically")); assert!(recommended.contains("provenance:")); assert!(recommended.contains("https://api.githubcopilot.com/mcp/")); assert!(recommended.contains("chrome-devtools-mcp@1.7.0")); @@ -599,8 +598,8 @@ mod tests { #[test] fn recommendations_state_execution_and_install_boundaries() { let text = recommended_mcp_text(&mut FakePresentation); - assert!(text.contains("nothing is installed automatically")); - assert!(text.contains("Suggested Codewhale plugins")); + assert!(text.contains("nothing installs automatically")); + assert!(text.contains("Suggested codewhale plugins")); assert!(text.contains("never downloads or")); assert!(text.contains("installs this binary")); assert!(text.contains("experimental")); diff --git a/crates/tui/src/localization.rs b/crates/tui/src/localization.rs index 1a8e71609c..d026f12870 100644 --- a/crates/tui/src/localization.rs +++ b/crates/tui/src/localization.rs @@ -5044,7 +5044,7 @@ mod tests { let expected = [ (Locale::Ca, "Treballadors de flota de la sessió actual:"), (Locale::De, "Flotten-Worker der aktuellen Sitzung:"), - (Locale::En, "Current-session fleet workers:"), + (Locale::En, "Fleet workers this session:"), (Locale::Es419, "Workers de flota de la sesión actual:"), (Locale::Fr, "Workers de la flotte de la session actuelle :"), (Locale::Hi, "वर्तमान सत्र के बेड़ा वर्कर:"), diff --git a/crates/tui/src/tui/approval/elevation.rs b/crates/tui/src/tui/approval/elevation.rs index f090909575..be476f8805 100644 --- a/crates/tui/src/tui/approval/elevation.rs +++ b/crates/tui/src/tui/approval/elevation.rs @@ -44,16 +44,12 @@ impl ElevationOption { #[cfg(test)] pub fn description(&self) -> &'static str { match self { - ElevationOption::WithNetwork => { - "Retry this tool call with outbound network access for downloads and HTTP requests" - } - ElevationOption::WithWriteAccess(_) => { - "Retry this tool call with additional writable filesystem scope" - } + ElevationOption::WithNetwork => "Retry with outbound network (downloads and HTTP)", + ElevationOption::WithWriteAccess(_) => "Retry with a wider writable scope", ElevationOption::FullAccess => { "Retry without sandbox limits; grants unrestricted filesystem and network access" } - ElevationOption::Abort => "Cancel this tool execution", + ElevationOption::Abort => "Cancel this run", } } diff --git a/crates/tui/src/tui/context_inspector.rs b/crates/tui/src/tui/context_inspector.rs index c314d24219..c04efe27cc 100644 --- a/crates/tui/src/tui/context_inspector.rs +++ b/crates/tui/src/tui/context_inspector.rs @@ -1084,8 +1084,8 @@ mod tests { let app = test_app(); let text = build_context_inspector_text(&app, Locale::En); assert!(text.contains("Session Context")); - assert!(text.contains("No file, directory, or media references recorded yet.")); - assert!(text.contains("No tool activity recorded yet.")); + assert!(text.contains("No file, folder, or media references yet.")); + assert!(text.contains("No tool activity yet.")); } fn schema_tool(name: &str, property_count: usize) -> Tool { diff --git a/crates/tui/src/tui/hotbar/actions.rs b/crates/tui/src/tui/hotbar/actions.rs index 9eb3f3e4e6..c369d2f9be 100644 --- a/crates/tui/src/tui/hotbar/actions.rs +++ b/crates/tui/src/tui/hotbar/actions.rs @@ -564,14 +564,14 @@ impl HotbarActionSource for BuiltinHotbarActionSource { "voice.toggle", "voice", "Voice input", - "Toggle voice capture from the terminal microphone.", + "Talk instead of type — uses your microphone.", AppHotbarKind::VoiceToggle, )); registry.register(AppHotbarAction::new( "session.compact", "compact", "Compact session", - "Compact the current conversation context.", + "Shrink this conversation to free context.", AppHotbarKind::SessionCompact, )); registry.register(AppHotbarAction::new( @@ -599,7 +599,7 @@ impl HotbarActionSource for BuiltinHotbarActionSource { "reasoning.cycle", "reason", "Cycle reasoning", - "Cycle the configured reasoning effort for the active provider.", + "Step through reasoning levels for the active provider.", AppHotbarKind::ReasoningCycle, )); registry.register(AppHotbarAction::new( @@ -627,7 +627,7 @@ impl HotbarActionSource for BuiltinHotbarActionSource { "trust.toggle", "trust", "Toggle trust", - "Enable or disable workspace trust mode.", + "Turn workspace trust on or off.", AppHotbarKind::TrustToggle, )); } diff --git a/crates/tui/src/tui/keybindings.rs b/crates/tui/src/tui/keybindings.rs index 09fb4528c9..87ce6e5de0 100644 --- a/crates/tui/src/tui/keybindings.rs +++ b/crates/tui/src/tui/keybindings.rs @@ -613,7 +613,7 @@ mod tests { assert_eq!(entry.section, KeybindingSection::Sessions); assert_eq!( crate::localization::tr(crate::localization::Locale::En, entry.description_id), - "Check for and install the latest Codewhale update (`/update install`)" + "Check for and install the latest codewhale update (`/update install`)" ); } diff --git a/crates/tui/src/tui/provider_picker.rs b/crates/tui/src/tui/provider_picker.rs index 082b888705..a07c57ce9b 100644 --- a/crates/tui/src/tui/provider_picker.rs +++ b/crates/tui/src/tui/provider_picker.rs @@ -8073,7 +8073,7 @@ mod tests { assert!(confirm.contains("no refresh, identity-provider or discovery requests")); assert!(confirm.contains("normal requests to the selected provider")); assert!( - confirm.contains("clears only Codewhale's consent record"), + confirm.contains("clears only codewhale's consent record"), "{confirm}" ); assert!(confirm.contains("external-revoke --provider openai-codex")); @@ -8136,7 +8136,7 @@ mod tests { let rendered = render_text(&picker, 96, 20); assert!(rendered.contains("xAI API key")); assert!(rendered.contains("Native device OAuth")); - assert!(rendered.contains("Codewhale-owned storage")); + assert!(rendered.contains("codewhale-owned storage")); picker.handle_key(key(KeyCode::Char('2'))); assert!(matches!( picker.handle_key(key(KeyCode::Enter)), @@ -8346,7 +8346,7 @@ mod tests { assert_eq!(picker.stage, Stage::ExternalConsentRevokeConfirm); let revoke_render = render_text(&picker, 120, 16); assert!( - revoke_render.contains("clears only Codewhale's consent record"), + revoke_render.contains("clears only codewhale's consent record"), "{revoke_render}" ); assert!( diff --git a/crates/tui/src/tui/ui/event_loop.rs b/crates/tui/src/tui/ui/event_loop.rs index 17221fdef8..2a51ab03b6 100644 --- a/crates/tui/src/tui/ui/event_loop.rs +++ b/crates/tui/src/tui/ui/event_loop.rs @@ -6546,7 +6546,7 @@ mod pod_workers_status_tests { fn current_session_pod_worker_status_keeps_the_english_session_boundary() { assert_eq!( current_session_pod_workers_status(Locale::En, 3), - "Current-session fleet workers: 3 total" + "Fleet workers this session: 3" ); } } diff --git a/crates/tui/src/tui/views/mod.rs b/crates/tui/src/tui/views/mod.rs index 1a9c7e03a2..c0e1106fb9 100644 --- a/crates/tui/src/tui/views/mod.rs +++ b/crates/tui/src/tui/views/mod.rs @@ -6189,11 +6189,11 @@ mod tests { empty.render(area, &mut empty_buf); let empty_text = buffer_text(&empty_buf, area); assert!( - empty_text.contains("No current-session fleet workers."), + empty_text.contains("No fleet workers this session."), "{empty_text}" ); assert!( - empty_text.contains("Configure roles and launch posture with /fleet."), + empty_text.contains("Set up roles with /fleet."), "{empty_text}" ); @@ -6209,7 +6209,7 @@ mod tests { "{english_text}" ); assert!( - english_text.contains("Sub-agent roles are current-session fleet worker roles."), + english_text.contains("Roles for this session's fleet workers."), "{english_text}" ); From c665b6c3fb3fcbcf75e5105dbd1d538dd781f53b Mon Sep 17 00:00:00 2001 From: CodeWhale Bot Date: Wed, 2 Sep 2026 14:04:53 -0700 Subject: [PATCH 3/3] copy(launch): warmer launch, setup, and help copy Rewrite launch/setup/onboarding/telemetry-notice/command-help copy in en.json (shorter, warmer; product name lowercased to codewhale, zero capitalized values left) and sync the inline English strings that render the same copy. Keys, placeholders, and parsed punctuation unchanged; test-pinned phrases (unknown-command head, context length/size, separate sign-in, Nothing deleted) preserved. Pixel-blessed launch goldens untouched (menu keeps Changelog). Tests: full codewhale-tui lib suite 11909 pass; cargo fmt clean; check-tui-product-vocabulary.sh clean. --- crates/tui/locales/en.json | 424 +++++++++--------- crates/tui/src/commands/groups/core/core.rs | 6 +- .../tui/src/commands/groups/utility/update.rs | 2 +- crates/tui/src/remote_control.rs | 16 +- crates/tui/src/tools/read_media.rs | 6 +- crates/tui/src/tools/review.rs | 4 +- crates/tui/src/tools/shell.rs | 2 +- crates/tui/src/tui/keybindings.rs | 2 +- .../tui/src/tui/onboarding/trust_directory.rs | 4 +- crates/tui/src/tui/phase_strip.rs | 6 +- crates/tui/src/tui/setup/mod.rs | 2 +- crates/tui/src/tui/ui/dispatch.rs | 4 +- crates/tui/src/tui/ui/event_loop.rs | 2 +- crates/tui/src/tui/ui/tests.rs | 14 +- 14 files changed, 247 insertions(+), 247 deletions(-) diff --git a/crates/tui/locales/en.json b/crates/tui/locales/en.json index aeb267a2d3..9a8c10519d 100644 --- a/crates/tui/locales/en.json +++ b/crates/tui/locales/en.json @@ -113,7 +113,7 @@ "ToastCouldNotSendIntoTurn": "Couldn't send into this turn; kept in the queue.", "ToastHookBlockedFollowUp": "A hook blocked the follow-up; it stayed in the queue.", "ToastOfflineQueuedCount": "Offline: {count} saved for later.", - "ComposerDispatchFailedRestored": "Not sent ({error}) — draft restored to the composer.", + "ComposerDispatchFailedRestored": "Message not sent ({error}); restored to composer.", "DispatchFailedQueued": "Send failed ({error}); kept {count} queued follow-up(s).", "DispatchFailedInitial": "Could not send your first message: {error}", "HistorySearchPlaceholder": "Search history...", @@ -123,18 +123,18 @@ "HistoryHintRestore": "Esc restore", "HistoryNoMatches": " No matches", "TranscriptReasoningExpand": "expand", - "TelemetryNoticeHeadline": "Help improve Codewhale?", - "TelemetryNoticeBody": "Codewhale counts: which version you run, OS and CPU family, session\nduration and outcome, and aggregate feature and error counters.\n\nIt never collects your conversations, code, prompts, files, repo or\nbranch names, model content, or credentials — and it never sends a\nper-turn or per-tool timeline of agent activity.\n\nYou are identified only by a random ID stored on this machine, replaced\nevery 90 days. Change your mind any time:\n codewhale config set telemetry false\n\nFull schema, field by field: docs/TELEMETRY.md", + "TelemetryNoticeHeadline": "Help improve codewhale?", + "TelemetryNoticeBody": "codewhale counts: which version you run, OS and CPU family, session\nduration and outcome, and aggregate feature and error counters.\n\nIt never collects your conversations, code, prompts, files, repo or\nbranch names, model content, or credentials — and it never sends a\nper-turn or per-tool timeline of agent activity.\n\nYou are identified only by a random ID stored on this machine, replaced\nevery 90 days. Change your mind any time:\n codewhale config set telemetry false\n\nFull schema, field by field: docs/TELEMETRY.md", "TelemetryNoticeCompactBody": "Counts: version, OS/CPU, session\ntime/result, feature/error totals.\nRandom local ID rotates every 90d.\nNever: chat/code/prompts/files/names;\nmodel content/credentials; turn/tools.\nSchema: docs/TELEMETRY.md\nOff: codewhale config set telemetry\nfalse", - "TelemetryNoticeChoiceKeep": "Yes, keep anonymous counts", - "TelemetryNoticeChoiceDisable": "No, turn off tracking", + "TelemetryNoticeChoiceKeep": "Yes, count me in", + "TelemetryNoticeChoiceDisable": "No, turn it off", "TelemetryNoticeActionChoose": "choose", "TelemetryNoticeActionConfirm": "confirm", "TelemetryNoticeActionExit": "exit", - "TelemetryNoticeReceiptEnabled": "Anonymous usage counts are on. Conversations and code are never collected. Change this in /settings; schema: docs/TELEMETRY.md", - "TelemetryNoticeReceiptDisabled": "Anonymous usage counting is off. You will not be asked again.", - "TelemetryNoticeReceiptEnabledUnsaved": "Anonymous usage counts are on for this session. Codewhale could not save this notice, so it will appear again. Change this in /settings; schema: docs/TELEMETRY.md", - "TelemetryNoticeReceiptDisabledUnsaved": "Anonymous usage counting is off for this session. Codewhale could not save the choice, so it will ask again next launch.", + "TelemetryNoticeReceiptEnabled": "Anonymous counts are on. Your conversations and code stay private. Change this in /settings; schema: docs/TELEMETRY.md", + "TelemetryNoticeReceiptDisabled": "Counting is off — we won't ask again.", + "TelemetryNoticeReceiptEnabledUnsaved": "Anonymous counts are on for this session. codewhale couldn't save this, so you'll see it again. Change it in /settings; schema: docs/TELEMETRY.md", + "TelemetryNoticeReceiptDisabledUnsaved": "Counting is off for this session. codewhale couldn't save the choice, so it will ask again next launch.", "TelemetryPreferenceEnabledNextLaunch": "Anonymous counts return next launch. Conversations and code stay private.", "TelemetryPreferenceDisabled": "Anonymous counts are off; local telemetry state was erased.", "TelemetryPreferenceDisabledWithWarning": "Anonymous usage counts are off, but one cleanup step needs attention: {detail}", @@ -344,24 +344,24 @@ "HelpFooterMove": " Up/Down move ", "HelpFooterJump": " PgUp/PgDn jump ", "HelpFooterClose": " Esc close ", - "CmdAnchorDescription": "Pin a fact that survives compaction (auto-injected into context)", - "CmdAttachDescription": "Attach image/video media; use @path for text files or directories", - "CmdCacheDescription": "Show prefix-cache hit/miss stats for the last N turns", - "CmdPreviewRequestDescription": "Preview the next request as a redacted manifest without sending it", - "CmdToolsDescription": "Inspect a bounded projection of the latest prepared tool request (read-only)", - "CmdEffortDescription": "Set the model's reasoning effort level (also /thinking)", - "CmdChangeDescription": "Show the latest changelog entry", - "CmdChangeHeader": "Latest Changelog", - "CmdChangeTranslationQueued": "English release notes are shown below. A translated version will be requested next; if the provider is unavailable, this English text is the fallback.", - "CmdChangeTranslationUnavailable": "English release notes are shown below. Translation is unavailable because the current session has no API key or is offline.", - "CmdChangePreviousVersion": "Previous version: {version} — run `/change {version}` to view it", - "CmdBalanceDescription": "Check the active provider account balance", - "CmdImportClaudeDescription": "Plan a reviewable import of Claude Code settings and MCP servers", + "CmdAnchorDescription": "Pin a fact that survives compaction", + "CmdAttachDescription": "Attach media (@path for text files or folders)", + "CmdCacheDescription": "Show cache hit/miss stats for recent turns", + "CmdPreviewRequestDescription": "Preview the next request (redacted) without sending it", + "CmdToolsDescription": "Peek at the prepared tool request (read-only)", + "CmdEffortDescription": "Set reasoning effort (also /thinking)", + "CmdChangeDescription": "Show what's new", + "CmdChangeHeader": "What's new", + "CmdChangeTranslationQueued": "English notes below. A translation was requested; this English text is the fallback if it fails.", + "CmdChangeTranslationUnavailable": "English notes below. No translation — this session has no API key or is offline.", + "CmdChangePreviousVersion": "Previous version: {version} — try `/change {version}`", + "CmdBalanceDescription": "Check your provider account balance", + "CmdImportClaudeDescription": "Plan a reviewable import of Claude Code settings and servers", "CmdClearDescription": "Clear conversation history", - "CmdCompactDescription": "Trigger context compaction to free up space", - "CmdPurgeDescription": "Let the agent surgically prune conversation history to free context space", - "CmdConfigDescription": "Inspect and change settings (raw keys as advanced detail)", - "CmdPermissionsDescription": "List and safely remove permission rules", + "CmdCompactDescription": "Shrink the context to free space", + "CmdPurgeDescription": "Let the agent prune history to free context", + "CmdConfigDescription": "Inspect and change settings — raw keys under advanced detail", + "CmdPermissionsDescription": "List or remove permission rules", "PermissionsListHeader": "Permission rules\nSource: active user permissions.toml\nPath: {path}\nFile status: {file_state}\nRule count: {count}", "PermissionsNoRules": "No permission rules yet.", "PermissionsFileMissing": "missing", @@ -381,13 +381,13 @@ "PermissionsUsage": "Usage: /permissions [list|remove [--confirm ]]", "PermissionsRuleNotFound": "No permission rule #{index}; run `/permissions list` again.", "PermissionsOperationFailed": "Could not update the permission rule: {error}", - "CmdConstitutionDescription": "Manage standing constitution law and previews", - "CmdContextDescription": "Open context inspector or source-map report", - "CmdCostDescription": "Show session cost breakdown", - "CmdDiffDescription": "Show file changes since session start", - "CmdEditDescription": "Revise and resubmit the last message", - "CmdExitDescription": "Exit the application", - "CmdExportDescription": "Copy a safe conversation export, or write it to an explicit file", + "CmdConstitutionDescription": "See and amend your constitution", + "CmdContextDescription": "Open the context inspector", + "CmdCostDescription": "Show what this session costs", + "CmdDiffDescription": "Show changes since this session started", + "CmdEditDescription": "Edit and resend your last message", + "CmdExitDescription": "Quit", + "CmdExportDescription": "Copy a safe export, or write it to a file", "CmdCopyDescription": "Copy the last completed assistant response to the clipboard", "CmdCopyNoOutput": "Nothing to copy yet — no completed response.", "CmdCopySuccess": "Copied the last response; a backup is at {path}.", @@ -398,20 +398,20 @@ "CmdCopyFailedNoBackup": "Couldn't copy ({error}), and no backup could be written. Use `/export file ` instead.", "CmdFeedbackDescription": "Generate a GitHub feedback URL", "CmdHfDescription": "Inspect Hugging Face MCP setup and concepts", - "CmdHelpDescription": "Understand concepts, commands, and keybindings", + "CmdHelpDescription": "Concepts, commands, and keybindings", "CmdProfileDescription": "Switch to a named config profile", - "CmdHomeDescription": "Show home dashboard with stats and quick actions", + "CmdHomeDescription": "Show the home dashboard", "CmdHooksDescription": "List configured lifecycle hooks (read-only)", "CmdAgentDescription": "Open a persistent sub-agent session", - "CmdGoalDescription": "Keep working toward one objective across turns", - "CmdInitDescription": "Generate AGENTS.md for project", - "CmdLspDescription": "Toggle LSP diagnostics on or off", - "CmdShareDescription": "Export current session as a shareable web URL", - "CmdJobsDescription": "Inspect and control background Bash jobs", + "CmdGoalDescription": "Work toward one objective across turns", + "CmdInitDescription": "Generate AGENTS.md for this project", + "CmdLspDescription": "Toggle LSP diagnostics", + "CmdShareDescription": "Share this session as a web URL", + "CmdJobsDescription": "Manage background shell jobs", "CmdDispatchDescription": "Send a codewhale cloud agent to raise a branch and open a PR", "CmdLinksDescription": "Show codewhale, community, and provider links", - "CmdLoadDescription": "Load session from file", - "CmdLogoutDescription": "Clear API key and return to setup", + "CmdLoadDescription": "Load a session from file", + "CmdLogoutDescription": "Sign out and return to setup", "CmdMcpDescription": "Open or manage MCP servers", "McpRecommendedUnknownId": "Unknown MCP suggestion. Run {recommendations_command} to see the list.", "McpRecommendationsHeading": "Suggested codewhale plugins (MCP components; nothing installs automatically)", @@ -481,34 +481,34 @@ "CmdPluginDetailApproval": "Approval: {approval}", "CmdPluginDetailPath": "Path: {path}", "CmdMemoryDescription": "Inspect or manage the persistent user-memory file", - "CmdModeDescription": "Switch permissions or open the mode picker", - "CmdModelDescription": "Switch or view current model", - "CmdModelsDescription": "Fetch live model IDs from the active API", + "CmdModeDescription": "Switch permissions, or pick a mode", + "CmdModelDescription": "Switch or show the current model", + "CmdModelsDescription": "List live model IDs from the active API", "CmdModelDbDescription": "Browse the bundled model database", - "CmdNetworkDescription": "Manage network allow and deny rules", + "CmdNetworkDescription": "Manage network allow/deny rules", "CmdUpdateDescription": "Check for and install a new codewhale release", - "CmdNoteDescription": "Add, list, edit, or remove workspace notes", - "CmdThemeDescription": "Switch theme or open the theme picker", - "CmdProviderDescription": "Switch the active provider and/or model", - "CmdAuthDescription": "Manage provider authentication flows", + "CmdNoteDescription": "Jot, list, edit, or drop workspace notes", + "CmdThemeDescription": "Pick a theme", + "CmdProviderDescription": "Switch provider or model", + "CmdAuthDescription": "Manage provider sign-in", "CmdLoginDescription": "Sign in to codewhale or store provider keys", - "CmdQueueDescription": "View or edit queued messages", + "CmdQueueDescription": "See or edit queued messages", "CmdQueueUsage": "Usage: /queue [list|send |edit |drop |clear]", "CmdQueueDraftHeader": "Editing queued message:", "CmdQueueNoMessages": "No queued messages", "CmdQueueListHeader": "Queued messages ({count}):", - "CmdQueueTip": "Tip: /queue send to send now, /queue drop to remove", - "CmdQueueAlreadyEditing": "Already editing a queued message. Send it or /queue clear to discard.", + "CmdQueueTip": "Tip: /queue send sends now, /queue drop removes", + "CmdQueueAlreadyEditing": "Already editing one — send it or /queue clear to discard.", "CmdQueueNotFound": "Queued message not found", "CmdQueueEditingStatus": "Editing queued message {index}", "CmdQueueEditingMessage": "Editing queued message {index} (press Enter to re-queue/send)", "CmdQueueDropped": "Dropped queued message {index}", "CmdQueueAlreadyEmpty": "Queue already empty", "CmdQueueCleared": "Queue cleared", - "CmdQueueMissingIndex": "Missing index. Usage: /queue edit or /queue drop ", - "CmdQueueIndexPositive": "Index must be a positive number", - "CmdQueueIndexMin": "Index must be >= 1", - "CmdRelayDescription": "Create a session relay (接力) for a fresh thread", + "CmdQueueMissingIndex": "Which one? Usage: /queue edit or /queue drop ", + "CmdQueueIndexPositive": "Use a positive number", + "CmdQueueIndexMin": "Use 1 or more", + "CmdRelayDescription": "Create a session relay for a fresh thread", "CmdRemoteControlDescription": "Resume this exact session from your codewhale web account", "CmdRemoteEnvDescription": "Open new hosted Work from a GitHub or CNB branch tip", "CmdRemoteEnvOverview": "Hosted Work starts a new environment from the branch tip available at GitHub or CNB.\n\nIt does not move this local folder or include unpushed commits, dirty or ignored files, secrets, or session state.\n\nUse {command} to open the hosted Work launcher.", @@ -516,28 +516,28 @@ "CmdRemoteEnvUnavailable": "codewhale could not resolve both a supported GitHub or CNB origin and a checked-out branch for this folder. Check out a branch and configure {origin} with an HTTPS or SSH URL, then try {command} again. Nothing was created or allocated.", "CmdRemoteEnvSourceCustodyPolicy": "codewhale does not upload, migrate, or sync local source into hosted Work. Use {command} to start from the branch tip available at GitHub or CNB. Unpushed commits, dirty or ignored files, secrets, and session state stay local.", "CmdRemoteEnvBrowserLabel": "codewhale hosted Work", - "CmdRenameDescription": "Rename the current session", + "CmdRenameDescription": "Rename this session", "CmdTitleDescription": "Set a tab/window title shown as [title] … in the terminal title", - "CmdRestoreDescription": "Roll back the workspace to a prior pre/post-turn snapshot. With no arg, lists recent snapshots.", + "CmdRestoreDescription": "Roll the workspace back to a turn snapshot. With no arg, lists recent ones.", "CmdRetryDescription": "Retry the last request", "CmdReviewDescription": "Run a structured code review on a file, diff, or PR", "CmdRlmDescription": "Open a persistent RLM context for a file or text", - "CmdSaveDescription": "Save session to file", - "CmdFullscreenDescription": "Paint on the alternate screen (the TUI owns the whole terminal)", - "CmdInlineDescription": "Paint inline at full terminal height, keeping the terminal's own scrollback", + "CmdSaveDescription": "Save this session to a file", + "CmdFullscreenDescription": "Fill the whole terminal (alternate screen)", + "CmdInlineDescription": "Stay inline, keeping the terminal's scrollback", "CmdForkDescription": "Fork the active conversation into a sibling session", - "CmdTreeDescription": "Show the session history as a tree (the leaf is the active branch)", - "CmdBranchDescription": "Move the active branch to an existing session entry without rewriting history", - "CmdResumeDescription": "Resume a session, optionally importing an exported session JSON file", - "CmdNewDescription": "Start a fresh saved session", - "CmdSessionsDescription": "Open session history picker", - "CmdSettingsDescription": "Open the typed settings editor", + "CmdTreeDescription": "Show session history as a tree (leaf = active branch)", + "CmdBranchDescription": "Point the active branch at an entry, without rewriting history", + "CmdResumeDescription": "Resume a session, or import a session JSON file", + "CmdNewDescription": "Start a fresh session", + "CmdSessionsDescription": "Browse past sessions", + "CmdSettingsDescription": "Open settings", "CmdSidebarDescription": "Place the rail (top/left/right/off) or pick its panel", - "CmdSkillDescription": "Activate a skill, or install/update/uninstall/trust a community skill", - "CmdSkillsDescription": "List local skills, filter by prefix, or browse the curated remote registry", + "CmdSkillDescription": "Use, install, or trust a skill", + "CmdSkillsDescription": "List local skills or browse the curated registry", "CmdStashDescription": "Park or restore a composer draft", - "CmdStatusDescription": "Show runtime session status", - "CmdStatuslineDescription": "Configure which items appear in the footer", + "CmdStatusDescription": "Show session status", + "CmdStatuslineDescription": "Choose footer items", "CmdStructcopyDescription": "Copy one bounded session object as redacted canonical JSON (human-only, never a model tool)", "CmdStructcopyKindTurn": "turn", "CmdStructcopyKindTool": "tool call", @@ -549,29 +549,29 @@ "CmdStructcopyPrepareFailed": "Could not prepare the selected {kind}: {error}", "CmdStructcopyClipboardQueued": "Structural copy ({kind}, {bytes} bytes) was queued for the terminal-client clipboard via tmux/OSC 52; delivery depends on terminal support and is not confirmed", "CmdStructcopyClipboardAccepted": "Structural copy ({kind}, {bytes} bytes) was handed to the clipboard; if no native clipboard was reachable, a terminal write was queued instead", - "CmdStructcopyClipboardFailed": "Couldn't reach the clipboard ({error}); nothing was written. Re-run with `stdout` to see the text.", + "CmdStructcopyClipboardFailed": "Couldn't reach the clipboard ({error}). Nothing was written; re-run with `stdout` to see the text.", "CmdStructcopyReceiptTooLarge": "Structural-copy receipt metadata exceeds the {bytes}-byte output cap; refusing to emit it", - "CmdFleetDescription": "Inspect and set up fleet members and orchestration state", - "CmdLaneDescription": "Inspect and control durable Lanes (running Workflows)", - "CmdWorkflowDescription": "Run a repeatable workflow when order or fan-out matters", - "CmdWorkflowsDescription": "Show workflow runs in this workspace (list, cancel)", - "CmdHotbarDescription": "Open Hotbar setup", + "CmdFleetDescription": "See and set up fleet members", + "CmdLaneDescription": "Watch and control durable Lanes", + "CmdWorkflowDescription": "Run a repeatable, ordered workflow", + "CmdWorkflowsDescription": "List or cancel workflow runs here", + "CmdHotbarDescription": "Set up the Hotbar", "CmdSetupDescription": "Open constitution-first setup", "CmdSubagentsDescription": "Compatibility shortcut for /fleet workers (current-session sub-agents)", - "CmdAdvisorDescription": "Toggle background advisor watcher on/off for this session", - "CmdSystemDescription": "Show current system prompt", + "CmdAdvisorDescription": "Toggle the background advisor for this session", + "CmdSystemDescription": "Show the system prompt", "CmdTaskDescription": "Manage background tasks", - "CmdTokensDescription": "Show token usage for session", - "CmdTranslateDescription": "Toggle output translation to the current system language on/off", - "CmdTranslateOff": "Output translation disabled (original model output shown)", - "CmdTranslateOn": "Output translation enabled: model responses will be shown in your system language", + "CmdTokensDescription": "Show token usage", + "CmdTranslateDescription": "Toggle output translation", + "CmdTranslateOff": "Translation off — showing original output", + "CmdTranslateOn": "Translation on — responses appear in your system language", "TranslationInProgress": "Translating...", "TranslationComplete": "Translated.", "TranslationFailed": "Couldn't translate.", - "CmdTrustDescription": "Manage workspace trust and the per-path allowlist", - "CmdWorkspaceDescription": "Show or switch the current workspace", - "CmdUndoDescription": "Remove last message pair", - "CmdVerboseDescription": "Toggle full live thinking in the transcript", + "CmdTrustDescription": "Manage workspace trust", + "CmdWorkspaceDescription": "Show or switch workspaces", + "CmdUndoDescription": "Drop the last exchange", + "CmdVerboseDescription": "Toggle live thinking in the transcript", "CmdCacheAdvice": "Hit/miss ratios over ~70% after the third turn indicate a stable cache prefix; \n lower than that on long sessions suggests prefix churn worth investigating (#263).", "CmdCacheFootnote": "* miss inferred from input − hit when the provider did not report it explicitly.\n", "CmdCacheHeader": "Cache telemetry — last {count} of {total} turn(s) (model: {model})\n", @@ -611,61 +611,61 @@ "HelpSectionSessions": "Sessions", "CmdTokensNotReported": "not reported", "CmdTokensReport": "Token Usage:\n ─────────────────────────────\n Active context: {active}\n Last API input: {input} (turn telemetry; may count repeated prefix across tool rounds)\n Last API output: {output}\n Cache hit/miss: {cache} (telemetry/cost only)\n Cumulative tokens: {total} (session usage telemetry)\n Priced amount: {cost}\n API messages: {api_messages}\n Chat messages: {chat_messages}\n Model: {model}", - "KbScrollTranscript": "Scroll transcript, navigate input history, or select composer attachments", - "KbNavigateHistory": "Navigate input history", + "KbScrollTranscript": "Scroll, browse input history, or pick attachments", + "KbNavigateHistory": "Browse input history", "KbBrowseHistory": "Browse conversation history", "KbScrollTranscriptAlt": "Scroll transcript", "KbScrollPage": "Scroll transcript by page", - "KbJumpTopBottom": "Jump to top / bottom of transcript", - "KbJumpTopBottomEmpty": "Jump to top / bottom (when input is empty)", - "KbJumpToolBlocks": "Jump between tool output blocks", + "KbJumpTopBottom": "Jump to top/bottom", + "KbJumpTopBottomEmpty": "Jump to top/bottom (empty input)", + "KbJumpToolBlocks": "Jump between tool blocks", "KbMoveCursor": "Move cursor in composer", - "KbJumpLineStartEnd": "Jump to start / end of line", - "KbDeleteChar": "Delete character before / after the cursor, or remove selected attachment", + "KbJumpLineStartEnd": "Jump to line start/end", + "KbDeleteChar": "Delete a character, or drop the attachment", "KbDeleteWord": "Delete the previous word", - "KbYank": "Yank from the kill buffer; with an empty composer, copy the focused transcript cell", - "KbToggleFileTree": "Toggle the file-tree sidebar", - "KbSelectText": "Select text; add Ctrl/Alt to select by word", + "KbYank": "Yank kill buffer; on empty input, copy the focused cell", + "KbToggleFileTree": "Toggle the file tree", + "KbSelectText": "Select text (Ctrl/Alt selects by word)", "KbSelectAllDraft": "Select the whole draft", - "KbClearDraft": "Clear the current draft", + "KbClearDraft": "Clear the draft", "KbRestoreClearedDraft": "Restore the cleared draft", "KbStashDraft": "Stash the current draft (`/stash pop` to restore)", - "KbSearchHistory": "Search prompt history and recover local drafts", - "KbInsertNewline": "Insert a newline in the composer", - "KbSendDraft": "Send when idle; queue while busy; empty composer sends the next queued follow-up now", - "KbSteerCurrentTurn": "Steer the current turn (sends normally while idle)", - "KbCloseMenu": "Close menu, cancel request, discard draft, or clear input", - "KbCancelOrExit": "Cancel request, or exit when idle", + "KbSearchHistory": "Search history and recover drafts", + "KbInsertNewline": "New line in the composer", + "KbSendDraft": "Send when idle; queue when busy; empty input sends the next queued item", + "KbSteerCurrentTurn": "Steer this turn (sends normally when idle)", + "KbCloseMenu": "Close menus, cancel, discard the draft, or clear input", + "KbCancelOrExit": "Cancel, or exit when idle", "KbShellControls": "Move the running shell wait to /jobs", "KbExitEmpty": "Exit when input is empty", "KbCommandPalette": "Open the command palette", - "KbSettings": "Open the typed settings editor", - "KbCancelBackgroundShellJobs": "Cancel all running background shell jobs (Activity sidebar)", + "KbSettings": "Open settings", + "KbCancelBackgroundShellJobs": "Cancel all background shell jobs", "KbFuzzyFilePicker": "Open the fuzzy file picker (insert @path on Enter)", - "KbCompactInspector": "Open compact session context inspector", - "KbCompactContext": "Compact the conversation context", - "KbLastMessagePager": "Open pager for the last message (when input is empty)", - "KbSelectedDetails": "Show raw detail for the selected tool or message; Ctrl+Alt+O opens the whole-turn overview", + "KbCompactInspector": "Open the context inspector", + "KbCompactContext": "Compact the conversation", + "KbLastMessagePager": "Page the last message (empty input)", + "KbSelectedDetails": "Show raw detail for the selection; Ctrl+Alt+O opens the turn overview", "KbToolDetailsPager": "Show raw detail for the selected item (Alt+V)", - "KbExternalEditor": "Open composer draft in external editor", - "KbLiveTranscript": "Open live transcript overlay (Ctrl+Shift+T; sticky-tail auto-scroll)", - "KbBacktrackMessage": "Backtrack to a previous user message (Left/Right step, Enter to rewind)", - "KbCompleteCycleModes": "Complete /command or cycle modes when the composer is empty (Plan → Work → Operate)", - "KbCycleThinking": "Cycle reasoning effort for the active provider (Ctrl+T)", + "KbExternalEditor": "Edit the draft externally", + "KbLiveTranscript": "Open the live transcript overlay", + "KbBacktrackMessage": "Rewind to an earlier message (Left/Right steps, Enter rewinds)", + "KbCompleteCycleModes": "Complete commands, or cycle modes on empty input (Plan → Work → Operate)", + "KbCycleThinking": "Cycle reasoning effort (Ctrl+T)", "KbCyclePermissions": "Cycle Access: Ask → Auto-Review → Full Access (Shift+Tab)", "KbJumpPlanAgentYolo": "Trigger hotbar slots", - "KbAltJumpPlanAgentYolo": "Jump to Plan / Work, or request Full Access (legacy alias, not a mode)", - "KbFocusSidebar": "Focus the Tasks / Agents / Context / Pinned rail panel", + "KbAltJumpPlanAgentYolo": "Jump to Plan/Work, or request Full Access (legacy alias)", + "KbFocusSidebar": "Focus the rail panel", "KbSessionPicker": "Open the session picker", "KbUpdateInstall": "Check for and install the latest codewhale update (`/update install`)", "UpdateChangedHint": "Updated codewhale: {previous} → {current}. Run /change to see what's new.", - "KbTerminalPaste": "Paste text using your local terminal", - "KbPasteAttach": "Paste text or attach an image from a local or forwarded graphical clipboard", + "KbTerminalPaste": "Paste via your terminal", + "KbPasteAttach": "Paste or attach an image from the clipboard", "KbCopySelection": "Copy the current codewhale selection", "ClipboardSshPasteHint": "SSH paste uses your local terminal: press Cmd+V on macOS or Ctrl+Shift+V on Linux/Windows.", - "KbContextMenu": "Open context actions for paste, selection, message details, context, and help", - "KbAttachPath": "Add a local text file or directory to context", - "KbHelpOverlay": "Open this help overlay (when input is empty)", + "KbContextMenu": "Context actions for paste, selection, and help", + "KbAttachPath": "Add a file or folder to context", + "KbHelpOverlay": "Open help (empty input)", "KbToggleHelp": "Toggle help overlay", "KbToggleHelpSlash": "Toggle help overlay", "HelpUsageLabel": "Usage:", @@ -675,7 +675,7 @@ "ClearConversation": "Conversation cleared", "ClearConversationBusy": "Nothing cleared — still busy. Try /clear again in a moment.", "ModelChanged": "Model changed: {old} →, {new}", - "LinksProjectTitle": "Codewhale & community:", + "LinksProjectTitle": "codewhale & community:", "LinksDocumentation": "Documentation:", "LinksCommunity": "Community & contribution:", "LinksGitHub": "GitHub:", @@ -684,7 +684,7 @@ "LinksTitle": "Provider Links:", "LinksDashboard": "Dashboard:", "LinksDocs": "Docs:", - "LinksKimiCodeRouteNote": "Kimi Code membership-plan route: `{route}` (plan console: `{console}`; use model k3). Codewhale never imports Kimi CLI credentials.", + "LinksKimiCodeRouteNote": "Kimi Code membership-plan route: `{route}` (plan console: `{console}`; use model k3). codewhale never imports Kimi CLI credentials.", "LinksTip": "Tip: Use the env var shown for your provider, or save the key with `codewhale auth set --provider `.", "SubagentsFetching": "Finding this session's sub-agents...", "SubagentsNoCurrentSessionPodWorkers": "No fleet workers this session.", @@ -729,7 +729,7 @@ "SubagentsRoleConsultant": "advisor", "SubagentsRoleCustom": "custom", "HelpUnknownCommand": "Unknown command: {topic} — try /help", - "HomeDashboardTitle": "Codewhale", + "HomeDashboardTitle": "codewhale", "HomeModel": "Model:", "HomeMode": "Mode:", "HomeWorkspace": "Workspace:", @@ -739,7 +739,7 @@ "HomeSubagents": "Fleet workers this session:", "HomeSkill": "Skill:", "HomeQuickActions": "Quick Actions", - "HomeQuickLinks": "/links - Codewhale, community & provider links", + "HomeQuickLinks": "/links - codewhale, community & provider links", "HomeQuickSkills": "/skills - List available skills", "HomeQuickConfig": "/config - Inspect and change settings", "HomeQuickSettings": "/settings - Show persistent settings", @@ -751,38 +751,38 @@ "HomeQuickRestore": "/restore - Roll files back to a turn snapshot", "HomeQuickTokens": "/tokens - Show session spend and context", "HomeModeTips": "Mode Tips", - "HomeAgentModeTip": "Act — direct work in the current session with tools", - "HomeAgentModeReviewTip": " /mode plan to research and present a plan first", + "HomeAgentModeTip": "Act — get work done with tools", + "HomeAgentModeReviewTip": " /mode plan researches and presents a plan first", "HomeAgentModeYoloTip": " Shift+Tab cycles permission: Ask → Auto-Review → Full Access", - "HomeYoloModeTip": "Act + Full Access — tools run without approval prompts", - "HomeYoloModeCaution": " Destructive operations can run immediately; prefer Ask when unsure", - "HomePlanModeTip": "Plan — research and design before implementing", - "HomePlanModeChecklistTip": " Present a plan and To-do progress, then switch to Act or Operate", - "HomeGoalModeTip": "Goal tracking - Set /goal to pursue objectives", + "HomeYoloModeTip": "Act + Full Access — tools run without asking", + "HomeYoloModeCaution": " Destructive tools run at once; prefer Ask when unsure", + "HomePlanModeTip": "Plan — research and design first", + "HomePlanModeChecklistTip": " Present the plan and progress, then switch to Act or Operate", + "HomeGoalModeTip": "Goal tracking — /goal pursues one objective", "OnboardLanguageTitle": "Choose your language", - "OnboardLanguageBlurb": "Pick the UI language. You can change it any time with `/settings set locale `.", + "OnboardLanguageBlurb": "Pick the UI language — change it anytime with `/settings set locale `.", "OnboardProviderTitle": "Choose your model provider", - "OnboardProviderBlurb": "Pick where your model runs. Hosted providers need a key; local runtimes can continue without one.", - "KimiCodePlanApiKeyHint": "For Kimi Code membership plans, create the plan-linked key at {console}.", + "OnboardProviderBlurb": "Pick where your model runs. Hosted providers need a key; local ones don't.", + "KimiCodePlanApiKeyHint": "For Kimi Code plans, create the linked key at {console}.", "KimiCodePlanRouteHint": "This route uses {route} with model k3; it is not Moonshot's public API route.", - "KimiCodePlanNoImportHint": "Codewhale does not import Kimi CLI credentials; paste a plan key you created yourself.", + "KimiCodePlanNoImportHint": "codewhale does not import Kimi CLI credentials; paste a plan key you made yourself.", "StepfunBillingRouteTitle": "StepFun billing route", - "StepfunBillingRouteIntro": "StepFun bills pay-as-you-go and Step Plan subscriptions on separate endpoints. Pick the one your key belongs to.", + "StepfunBillingRouteIntro": "StepFun bills pay-as-you-go and Step Plan on separate endpoints. Pick your key's home.", "StepfunBillingRoutePaygOption": "Pay-as-you-go (token pricing)", "StepfunBillingRoutePlanOption": "Step Plan subscription (plan allowance)", - "StepfunPlanApiKeyHint": "For StepFun Step Plan subscriptions, use the key issued for your Step Plan, not a pay-as-you-go key.", - "StepfunPlanRouteHint": "This route uses {route} and is billed against your Step Plan allowance.", - "OnboardApiKeyRejectedEnv": "The {provider} API key from {env} was rejected. Paste a valid key to save it to {path}, or update the environment variable.", - "OnboardTrustTitle": "Know this workspace", - "OnboardTrustQuestion": "Should Codewhale work with the instructions and files in this workspace?", + "StepfunPlanApiKeyHint": "Use your Step Plan key here, not a pay-as-you-go key.", + "StepfunPlanRouteHint": "This route uses {route}, billed to your Step Plan.", + "OnboardApiKeyRejectedEnv": "The {provider} key from {env} didn't work. Paste a good key to save it to {path}, or update the variable.", + "OnboardTrustTitle": "Can we trust this workspace?", + "OnboardTrustQuestion": "Should codewhale work with the instructions and files in this workspace?", "OnboardTrustLocationPrefix": "Workspace ", - "OnboardTrustRiskHint": "Untrusted files can try to redirect the agent through prompt injection.", - "OnboardTrustEffectHint": "Trust is recorded for this Codewhale installation and enables workspace tools and hooks.", - "OnboardTrustEnterHint": "Press 1 or Y to trust, 2 or U to continue without trusting, or 3, N, or Esc to quit Codewhale.", + "OnboardTrustRiskHint": "Untrusted files can misdirect the agent (prompt injection).", + "OnboardTrustEffectHint": "Trust is recorded for this codewhale installation and enables workspace tools and hooks.", + "OnboardTrustEnterHint": "Press 1 or Y to trust, 2 or U to continue without trusting, or 3, N, or Esc to quit codewhale.", "OnboardTrustUntrustedNotice": "Continuing without workspace trust — tools and hooks stay restricted.", - "OnboardOfflineOption": "Ctrl+O — explore offline: look around now, connect a provider later.", - "OnboardOfflineNotice": "Exploring offline. Nothing is connected yet — run /provider when you want to connect.", - "OnboardWelcomeTitle": "Codewhale works with you in this folder.", + "OnboardOfflineOption": "Ctrl+O — look around offline; connect later.", + "OnboardOfflineNotice": "Exploring offline — run /provider whenever you're ready to connect.", + "OnboardWelcomeTitle": "codewhale works with you in this folder.", "OnboardWelcomeLead": "Let's get you ready.", "OnboardWelcomeBegin": "begin", "OnboardActionBack": "back", @@ -794,15 +794,15 @@ "OnboardProviderOffline": "explore offline", "OnboardTrustActionTrust": "trust and continue", "OnboardTrustActionSkip": "continue without trusting", - "OnboardTrustActionQuit": "quit Codewhale", + "OnboardTrustActionQuit": "quit codewhale", "OnboardReadyTitle": "You're ready.", - "OnboardReadyLead": "Tell Codewhale what you want done.", + "OnboardReadyLead": "Tell codewhale what you want done.", "OnboardReadyStart": "start", "OnboardReadyCustomize": "customize the look later", - "OnboardSeedCodeProject": "Explain what this project does and list its main entry points.", + "OnboardSeedCodeProject": "Explain this project and list its main entry points.", "OnboardSeedFolder": "Look at this folder and suggest a good first task.", "SetupWizardTitle": "Setup", - "SetupWizardWhy": "This shell records setup progress in setup_state.json; config changes are only applied by explicit step actions.", + "SetupWizardWhy": "Setup progress lives in setup_state.json; steps only change config when you say so.", "SetupWizardProgress": "Step", "SetupActionBack": "back", "SetupActionContinue": "continue", @@ -838,43 +838,43 @@ "SetupStatusSkipped": "skipped", "SetupStatusFailed": "failed", "SetupStepLanguageTitle": "Language", - "SetupStepLanguageWhy": "Choose the setup language first so later setup screens and constitution copy are understandable.", + "SetupStepLanguageWhy": "Pick the setup language first, so every later screen reads clearly.", "SetupStepProviderModelTitle": "Provider and model", - "SetupStepProviderModelWhy": "Choose the first interpreter of your code: the provider and model Codewhale will work with. Working credentials are not re-entered here.", + "SetupStepProviderModelWhy": "Choose the first interpreter of your code: the provider and model codewhale will work with. Working credentials are not re-entered here.", "SetupStepTrustSandboxTitle": "Runtime posture", - "SetupStepTrustSandboxWhy": "Review trust, sandbox, approval, shell, and network policy separately from constitutional guidance.", + "SetupStepTrustSandboxWhy": "Review trust, sandbox, approvals, shell, and network — separate from guidance.", "SetupStepOperateFleetTitle": "Operate and fleet", - "SetupStepOperateFleetWhy": "Operate can use the built-in team immediately. Roles without a custom route use this session's model; fleet setup is only for customization.", + "SetupStepOperateFleetWhy": "Operate works with the built-in team right away. Roles borrow this session's model unless you customize them in fleet setup.", "SetupStepToolsMcpTitle": "Tools and MCP", - "SetupStepToolsMcpWhy": "Inspect optional tool and MCP readiness without blocking the constitution checkpoint.", + "SetupStepToolsMcpWhy": "Check tools and MCP readiness — optional, never blocks the checkpoint.", "SetupStepHotbarTitle": "Hotbar", - "SetupStepHotbarWhy": "Configure common route and command shortcuts after the core setup path is safe.", + "SetupStepHotbarWhy": "Set up route and command shortcuts once the core path is safe.", "SetupStepRemoteRuntimeTitle": "Remote runtime", "SetupStepRemoteRuntimeWhy": "Keep remote setup visible but optional for local-first users.", "SetupStepPersistenceTitle": "Persistence", - "SetupStepPersistenceWhy": "Review where setup state, config, constitution, memory, and notes live without reading their contents.", + "SetupStepPersistenceWhy": "See where setup state, config, constitution, memory, and notes live — contents stay private.", "SetupStepConstitutionTitle": "Working agreement", "SetupStepConstitutionWhy": "This agreement guides behavior, not runtime permissions.", "SetupStepVerificationTitle": "Review", - "SetupStepVerificationWhy": "Summarize setup status and show which steps are verified, skipped, or still need action.", + "SetupStepVerificationWhy": "See what's verified, skipped, or still needs you.", "SetupCheckpointLayerOrder": "Layer order: bundled Constitution -> user-global constitution -> repo constitution -> AGENTS/project instructions -> memory/handoff -> current request.", - "SetupCheckpointDoneBundled": "Constitution checkpoint complete: using bundled/default law.", - "SetupCheckpointDoneGuided": "Constitution ratified — your standing law is saved. Amend anytime with /constitution.", - "SetupCheckpointDoneKept": "Constitution kept — your existing law stands, unchanged. Amend anytime with /constitution.", - "SetupCheckpointDeferred": "Constitution checkpoint deferred: bundled/default law applies until you return to /setup.", - "SetupStepSkipped": "Setup step skipped and saved.", - "SetupStepRetryRecorded": "Setup step marked for retry.", - "SetupLanguageReviewed": "Setup language recorded.", + "SetupCheckpointDoneBundled": "Checkpoint done: bundled law applies.", + "SetupCheckpointDoneGuided": "Ratified — your standing law is saved. Amend anytime with /constitution.", + "SetupCheckpointDoneKept": "Kept — your existing law stands. Amend anytime with /constitution.", + "SetupCheckpointDeferred": "Deferred — bundled law applies until you return to /setup.", + "SetupStepSkipped": "Step skipped and saved.", + "SetupStepRetryRecorded": "Step marked for retry.", + "SetupLanguageReviewed": "Language recorded.", "SetupConstitutionChoiceLabel": "Choice:", "SetupConstitutionSourceLabel": "Source:", "SetupConstitutionValidityLabel": "Validity:", "SetupConstitutionPreviewLabel": "Preview hash:", "SetupConstitutionExistingLabel": "Existing file:", "SetupConstitutionExpertOverrideLabel": "Expert override:", - "SetupConstitutionGuidedHint": "1-6 tune the draft, G previews, G again ratifies. Guidance only: it never changes runtime approval, sandbox, shell, network, trust, or MCP permissions.", - "SetupConstitutionGuidedAnswersHint": "Guided answers save user-global preferences only. The bundled core stays active; execution stays with runtime policy and future opt-ins.", - "SetupConstitutionExistingDefaultDetail": "Enter keeps it unchanged. C opens all agreement options.", - "SetupConstitutionRepairDefaultDetail": "Enter uses the safe bundled agreement without changing this file. C opens repair options.", + "SetupConstitutionGuidedHint": "1-6 tune the draft, G previews, G again ratifies. Guidance never touches runtime approvals, sandbox, shell, network, trust, or MCP.", + "SetupConstitutionGuidedAnswersHint": "Guided answers save only your global preferences. The bundled core stays on; runtime policy still governs execution.", + "SetupConstitutionExistingDefaultDetail": "Enter keeps it. C shows every option.", + "SetupConstitutionRepairDefaultDetail": "Enter uses the safe bundled agreement; the file stays untouched. C shows repairs.", "SetupConstitutionPurposeLabel": "Purpose:", "SetupConstitutionAutonomyLabel": "Initiative:", "SetupConstitutionEvidenceLabel": "Evidence:", @@ -897,7 +897,7 @@ "SetupOperateReadinessLabel": "Operate readiness:", "SetupOperateReviewHint": "Enter records this setup snapshot.", "SetupOperateReviewed": "Operate/fleet readiness recorded.", - "SetupOperateNeedsActionSaved": "Operate/fleet still needs action; recorded for setup report.", + "SetupOperateNeedsActionSaved": "Operate/fleet still needs you; noted in the report.", "SetupHotbarBindingsLabel": "Hotbar bindings:", "SetupHotbarActionsLabel": "Bindable actions:", "SetupHotbarReviewHint": "Enter records this setup snapshot. Press H to customize slots.", @@ -918,7 +918,7 @@ "SetupRemoteModeChatBridge": "Chat app:", "SetupRemoteStatusDisabled": "not available", "SetupRemoteStatusReady": "ready", - "SetupRemoteStatusNeedsAction": "needs something", + "SetupRemoteStatusNeedsAction": "needs setup", "SetupRemoteReviewHint": "Enter records this setup snapshot. Press R to preview.", "SetupRemotePreviewTitle": "Remote runtime on-ramp", "SetupRemoteReviewed": "Remote runtime on-ramp recorded.", @@ -930,24 +930,24 @@ "SetupPersistenceNotesLabel": "Notes:", "SetupPersistenceReviewHint": "Enter records this setup snapshot.", "SetupPersistenceReviewed": "Persistence paths recorded.", - "SetupProviderModelReadyHint": "Enter records this provider/model route; press P for provider setup or M for model routes.", - "SetupProviderModelNeedsActionHint": "Enter records provider/model as needs-action and continues; press P to fix credentials or M to inspect routes.", + "SetupProviderModelReadyHint": "Enter records this route; P opens provider setup, M shows model routes.", + "SetupProviderModelNeedsActionHint": "Enter notes it as needs-action and moves on; P fixes credentials, M inspects routes.", "SetupProviderModelReviewed": "Provider/model readiness recorded.", - "SetupProviderModelNeedsActionSaved": "Provider/model still needs action; recorded for setup report.", + "SetupProviderModelNeedsActionSaved": "Provider/model still needs you; noted in the report.", "SetupRuntimePostureBoundary": "Runtime posture is enforced config; constitution guidance never changes it silently.", - "SetupRuntimePostureReviewHint": "Enter records this setup snapshot. Press M for work mode or C for config.", - "SetupRuntimePostureReviewed": "Runtime posture reviewed; no config changed.", + "SetupRuntimePostureReviewHint": "Enter records it. M picks the work mode, C opens config.", + "SetupRuntimePostureReviewed": "Posture reviewed — nothing changed.", "SetupRuntimePresetSelectedLabel": "Selected preset:", "SetupRuntimePresetDiffLabel": "Config diff:", "SetupRuntimePresetAskFirstTitle": "Ask-first", - "SetupRuntimePresetAskFirstDescription": "Plan by default, shell hidden, read-only sandbox.", + "SetupRuntimePresetAskFirstDescription": "Plans first; shell hidden; read-only sandbox.", "SetupRuntimePresetNormalAgentTitle": "Normal agent", - "SetupRuntimePresetNormalAgentDescription": "Agent by default, approval prompts, shell visible.", + "SetupRuntimePresetNormalAgentDescription": "Works by default, asks first, shell visible.", "SetupRuntimePresetHighTrustTitle": "High-trust local", - "SetupRuntimePresetHighTrustDescription": "Full Access by default for trusted local work; no hidden constitution mutation.", + "SetupRuntimePresetHighTrustDescription": "Full Access by default here; never rewrites your constitution silently.", "SetupRuntimePresetPreviewTitle": "Runtime Posture Preset Preview", - "SetupRuntimePresetSafetyFloor": "Safety floor: auth/OAuth failures, blocked policy outcomes, publish-like actions, and hold-for-review gates can still stop the run.", - "SetupRuntimePresetApplyHint": "Press A to preview this exact diff; press A again after preview to apply it.", + "SetupRuntimePresetSafetyFloor": "Safety floor: auth failures, blocked policies, publish-like actions, and review holds can still stop the run.", + "SetupRuntimePresetApplyHint": "Press A to preview; press A again to apply.", "SetupRuntimePresetApplied": "Runtime preset applied.", "SetupRuntimeProjectOverrideLabel": "Project override:", "SetupRuntimeProjectOverrideNone": "none detected for approval_policy or sandbox_mode", @@ -964,12 +964,12 @@ "SetupReportOptional": "optional", "SetupReportRowsLabel": "Step status:", "SetupReportNextActionLabel": "Next action:", - "SetupReportNextActionNone": "No blocking setup action recorded.", - "SetupReportNextActionConstitution": "Complete the constitution checkpoint or choose bundled/default.", - "SetupReportNextActionProvider": "Review provider/model readiness or run /setup provider; use /provider setup for a specific provider.", - "SetupReportNextActionRuntime": "Review runtime posture or use /config.", - "SetupReportNextActionOperate": "Review Operate/fleet readiness before durable multi-worker runs.", - "SetupReportNextActionRequired": "Review the remaining required setup steps.", + "SetupReportNextActionNone": "Nothing blocking — you're set.", + "SetupReportNextActionConstitution": "Finish the constitution checkpoint, or take the bundled one.", + "SetupReportNextActionProvider": "Check provider/model readiness (/setup provider), or /provider setup for one provider.", + "SetupReportNextActionRuntime": "Review runtime posture in /config.", + "SetupReportNextActionOperate": "Review Operate/fleet readiness before durable runs.", + "SetupReportNextActionRequired": "Finish the remaining required steps.", "SetupReportRecorded": "Setup report recorded.", "CtxMenuTitle": " Right click ", "CtxMenuCopySelection": "Copy selection", @@ -1046,7 +1046,7 @@ "ApprovalChooseAction": "Enter selects, or press y/a/d directly", "ApprovalIntentLabel": "Intent: ", "ApprovalMoreLines": " … (+{count} lines)", - "ApprovalAutoDeniedSession": "Auto-denied {tool}: you denied a matching request earlier in this run. Restart codewhale to reconsider it.", + "ApprovalAutoDeniedSession": "Auto-denied {tool}: a matching request was denied earlier during this codewhale run. Restart codewhale to reconsider it.", "ElevationTitleSandboxDenied": " ⚠, Sandbox Denied ", "ElevationTitleRequired": " Sandbox Elevation Required ", "ElevationFieldTool": " Tool: ", @@ -1131,9 +1131,9 @@ "ToolReceiptDone": "done", "ToolReceiptLinesSingular": "1 line", "ToolReceiptLinesPlural": "{count} lines", - "CmdVoiceDescription": "Toggle voice input: record speech and transcribe into the composer", - "CmdVoiceSendDescription": "Toggle voice auto-send: submit when the transcript ends with \"send it\"", - "CmdVoiceControlDescription": "Toggle voice control: AI-assisted dictation aware of the composer text", + "CmdVoiceDescription": "Dictate into the composer", + "CmdVoiceSendDescription": "Auto-send voice: submits when you say \"send it\"", + "CmdVoiceControlDescription": "Smarter dictation that sees the composer", "VoiceEnabled": "Voice on — speak to record.", "VoiceDisabled": "Voice off.", "VoiceSendEnabled": "Voice auto-send on.", @@ -1224,7 +1224,7 @@ "SetupGuidedEvidenceReleaseReceipts": "release receipts", "SetupGuidedNotes": "Guided answers: purpose={purpose}; initiative={initiative}; evidence={evidence}; communication={communication}; privacy={privacy}; principles={principles}. {notes} Free-text principles are advisory and do not change approval, sandbox, shell, network, trust, or MCP permissions.", "SetupToolsMcpHotbarLabel": "Hotbar sources:", - "SetupToolsMcpNeedsActionSaved": "Tools/MCP still needs action; recorded for setup report (does not block first-run).", + "SetupToolsMcpNeedsActionSaved": "Tools/MCP still needs you; noted in the report (first run isn't blocked).", "SetupToolsMcpPreviewTitle": "Tools / MCP safe on-ramps", "SetupToolsMcpOnRampText": "Tools, MCP, Skills & Plugins — Safe On-Ramps\n\n/setup only reads local inventory. It never starts MCP servers, installs skills, runs plugins, or executes untrusted commands.\n\nCurrent inventory:\n- MCP: {mcp_result}\n- Skills: {skills_result}\n- Tools dir: {tools_result}\n- Plugins: {plugins_result}\n- Hotbar (shared adapters): {hotbar_result}\n\nPaths (redacted home):\n- MCP config: {mcp_path}\n- Skills: {skills_path}\n- Plugins: {plugins_path}\n\nSafe bootstrap (run yourself in a normal terminal or TUI command):\n- MCP: /mcp · codewhale mcp init · codewhale doctor\n- Skills: /skills · codewhale setup --skills · /skills install \n- Plugins: /plugin · codewhale setup --plugins\n- Tools dir: codewhale setup --tools\n\nSide-effectful actions always require explicit confirmation. Plugin commands stay distinct from slash commands; the Hotbar plugin source remains deferred until approval gates land.\n\nSee docs/MCP.md and docs/skills/README.md for what still needs manual external setup.", "SetupToolsMcpDshLabel": "DeepSeek Harness (dsh):", @@ -1232,14 +1232,14 @@ "HotbarActionModeOperateName": "Operate mode", "HotbarActionModeOperateDescription": "Put your fleet to work in parallel.", "HomeOperateModeTip": "Operate — put your fleet to work in parallel", - "HomeOperateModeFleetTip": " Built-in roles use this session's model; /fleet setup customizes them", + "HomeOperateModeFleetTip": " Roles borrow this session's model; /fleet setup customizes them", "HelpSubtitle": "Concepts, commands, and keybindings", "CommandPaletteTitle": "Command", "CommandPaletteSubtitle": "Find and run one action", "ConfigSubtitle": "Settings first; raw keys under advanced detail", "LaunchStartTitle": "Start here", - "LaunchWorkDescription": "Use this folder with local tools; changes follow your approval policy.", - "LaunchChatDescription": "Conversation and planning only; no file changes.", + "LaunchWorkDescription": "Work in this folder; changes follow your approval policy.", + "LaunchChatDescription": "Just talk and plan — nothing changes on disk.", "LaunchWorkspaceGitReady": "Workspace · {name} · Git workspace", "LaunchWorkspaceFolderReady": "Workspace · {name} · local folder", "LaunchProviderConfigured": "Provider · configured", @@ -1251,8 +1251,8 @@ "LaunchProviderConfiguredShort": "provider set", "LaunchProviderSetupShort": "provider setup", "LaunchMenuChangelog": "Changelog", - "LaunchWorktreePrompt": "Name the branch/worktree, or press Enter for an automatic name.", - "LaunchWorktreeNeedsGit": "New worktree requires a Git repository.", + "LaunchWorktreePrompt": "Name the branch/worktree, or Enter for an auto name.", + "LaunchWorktreeNeedsGit": "Worktrees need a Git repo.", "LaunchWorktreeNameLabel": "worktree name", "LaunchHintMove": "move", "LaunchHintOpen": "open", @@ -1261,7 +1261,7 @@ "LaunchSavedSessionsPlural": "{count} saved sessions", "LaunchCreatingWorktree": "Creating worktree…", "LaunchWorktreeFailed": "Could not create the worktree: {error}", - "LaunchNoSavedSessions": "No saved sessions for this workspace.", + "LaunchNoSavedSessions": "No saved sessions here yet.", "LaunchComposerHint": "Enter send · Shift+Enter new line · Esc back", "LaunchNoModelConnected": "no model connected", "LaunchRunCommand": "run {command}", @@ -1624,7 +1624,7 @@ "ThinkingControlledByAutoRouting": "Auto routing controls thinking; pick a fixed model first.", "SavedAsStartupDefault": "saved as startup default", "ModeAlreadyActiveSavedAsDefault": "Already in {mode} — saved as startup default.", - "StartupDefaultNotSaved": "{setting} couldn't be saved: {error}", + "StartupDefaultNotSaved": "{setting} was not saved: {error}", "StartupDefaultSubjectMode": "startup mode", "StartupDefaultSubjectThinking": "thinking level", "StartupDefaultSubjectModel": "model", @@ -1645,12 +1645,12 @@ "KbReasoningDetail": "Open reasoning detail for the selected or current turn", "KbTurnInspector": "Open Turn Inspector", "CmdTurnInspectDescription": "Open the whole-turn inspector", - "CmdAutomationDescription": "Manage durable scheduled automations", + "CmdAutomationDescription": "Manage scheduled automations", "AutomationUsage": "Usage: /automation [list|show |pause |resume |delete [--confirm ]|run ]", "AutomationManagerUnavailable": "Automations aren't available this session.", "AutomationListFailed": "Could not list automations: {error}", "AutomationActionFailed": "Could not {action} automation {id}: {error}", - "AutomationEmpty": "No automations yet. The `automation` tool creates one.", + "AutomationEmpty": "No automations yet. Use the `automation` tool to create one.", "AutomationListHeading": "Scheduled automations", "AutomationNoun": "Automation", "AutomationStatusLabel": "status", @@ -1693,8 +1693,8 @@ "AutomationReceiptDeleted": "deleted", "AutomationRunLabel": "run", "AutomationDeletedRunsDetail": "recorded runs deleted: {run_count}", - "AutomationDeletePreview": "Not armed — nothing was deleted.\nAutomation: {id} ({name})\nRecorded runs: {run_count}\nTo delete it and its history, run:\n{command}", - "AutomationDeleteConfirmationStale": "That confirmation expired for {id}; nothing was deleted. Check {command} and try again.", + "AutomationDeletePreview": "Not armed. Nothing was deleted.\nAutomation: {id} ({name})\nRecorded runs: {run_count}\nTo delete it and its history, run:\n{command}", + "AutomationDeleteConfirmationStale": "Deletion confirmation no longer matches automation {id}; nothing was deleted. Review the current state with {command}.", "WhaleStateResting": "Resting", "WhaleStateThinking": "Thinking", "WhaleStateWorking": "Working", @@ -1784,7 +1784,7 @@ "AutoReviewReceiptGuardianDenied": "Auto-Review denied '{tool}' ({risk} risk, model guardian): {reason}", "AutoReviewReceiptGuardianUnavailable": "Auto-Review could not review '{tool}' ({reason}); denied, fail closed", "AutoReviewReceiptDeterministicBlocked": "Auto-Review blocked '{tool}' (deterministic policy): {reason}", - "AutoReviewReceiptHeld": "Auto-Review held '{tool}' (needs a person); denied — switch to Ask", + "AutoReviewReceiptHeld": "Auto-Review held '{tool}' without pausing; denied (needs a person — switch to Ask)", "FooterHintEscInterrupt": "Esc to interrupt", "PostureHintEnterAgain": "{enter} again to send now · {steer} steers", "PermissionsPostureHeader": "Access now: {posture}", @@ -1819,7 +1819,7 @@ "GoalReceiptSetOperate": "◆ goal set · Operate works till it's verified · /goal edits it", "GoalControlAccepted": "Goal control saved — applies at the next safe point.", "GoalControlRuntimeUnavailable": "Goal control saved, but the runtime is down. It returns after restart.", - "GoalStatusIdleHint": "paused — send a message or /goal resume", + "GoalStatusIdleHint": "not running now — send a message or /goal resume to continue", "CmdAutoDescription": "Work with Auto-Review — skip a goal or workflow", "AutoReceiptOn": "Auto-Review on. /goal keeps one objective; /workflow runs a script.", "AutoReceiptPlanNote": "Plan stays Read Only until you switch to Work or Operate.", @@ -1851,8 +1851,8 @@ "ConfigLabelProviderTemplates": "Provider templates", "ConfigActionOpenProviderTemplates": "Enter opens template list", "ConfigHintProviderTemplates": "P in /provider; C-t tests /models without treating 2xx as model-ready", - "ProviderConnectionChecked": "Connection ok (/models returned 2xx); model availability still unchecked.", - "ProviderConnectionCheckedPickModel": "Connection ok (/models returned 2xx). Pick a default model — availability still unchecked.", + "ProviderConnectionChecked": "Connection checked (/models returned 2xx). Model availability is not checked.", + "ProviderConnectionCheckedPickModel": "Connection checked (/models returned 2xx). Pick a default model; model availability is not checked.", "ProviderTestConnectionNeedKey": "No API key saved for {provider}. Add one first, then press T to test.", "ProviderTestConnectionFailed": "Could not reach {provider}: {error}", "ProviderTestConnectionNoEndpoint": "{provider} exposes no /models endpoint; reachability unprobed.", @@ -2022,6 +2022,6 @@ "LaunchMenuNewWorktree": "New worktree", "LaunchMenuResume": "Resume session", "LaunchMenuQuit": "Quit", - "LaunchNoticeClaude": "Coming from Claude Code? Resume your session with ctrl+r", + "LaunchNoticeClaude": "From Claude Code? Resume with ctrl+r", "ReceiptSessionHooks": "hooks {count}" } diff --git a/crates/tui/src/commands/groups/core/core.rs b/crates/tui/src/commands/groups/core/core.rs index 9ddec55472..e52241270d 100644 --- a/crates/tui/src/commands/groups/core/core.rs +++ b/crates/tui/src/commands/groups/core/core.rs @@ -1607,7 +1607,7 @@ mod tests { let result = codewhale_links(&mut app); assert!(result.message.is_some()); let msg = result.message.unwrap(); - assert!(msg.contains("Codewhale & community")); + assert!(msg.contains("codewhale & community")); assert!(msg.contains("https://codewhale.net/en/docs")); assert!(msg.contains("https://codewhale.net/en/community")); assert!(msg.contains("https://github.com/Hmbown/CodeWhale")); @@ -1700,7 +1700,7 @@ mod tests { let result = home_dashboard(&mut app); assert!(result.message.is_some()); let msg = result.message.unwrap(); - assert!(msg.contains("Codewhale")); + assert!(msg.contains("codewhale")); assert!(!msg.contains("codewhale Home Dashboard")); assert!(msg.contains("Model:")); assert!(msg.contains("Mode:")); @@ -1753,7 +1753,7 @@ mod tests { assert!(msg.contains("/workspace - Switch folders or worktrees")); assert!(msg.contains("/restore - Roll files back to a turn snapshot")); assert!(msg.contains("/tokens - Show session spend and context")); - assert!(msg.contains("/links - Codewhale, community & provider links")); + assert!(msg.contains("/links - codewhale, community & provider links")); assert!(msg.contains("/config - Inspect and change settings")); assert!( !msg.lines() diff --git a/crates/tui/src/commands/groups/utility/update.rs b/crates/tui/src/commands/groups/utility/update.rs index a7e305c4ad..45f5f74c98 100644 --- a/crates/tui/src/commands/groups/utility/update.rs +++ b/crates/tui/src/commands/groups/utility/update.rs @@ -208,7 +208,7 @@ fn run_updater(updater: &Path, mode: UpdateMode) -> CommandResult { CommandResult::message(format!("{}\n\n{transcript}", install_preamble(updater))) } UpdateMode::Install => CommandResult::message(format!( - "{transcript}\n\nRestart Codewhale to run the updated binary." + "{transcript}\n\nRestart codewhale to run the updated binary." )), } } diff --git a/crates/tui/src/remote_control.rs b/crates/tui/src/remote_control.rs index cfcf1db8cc..14ac1142f0 100644 --- a/crates/tui/src/remote_control.rs +++ b/crates/tui/src/remote_control.rs @@ -4403,7 +4403,7 @@ fn parse_remote_command(value: &Value, expected_run_id: &str) -> Result Result Result Result RemoteControlRequest::Interrupt, @@ -4532,7 +4532,7 @@ fn parse_remote_command(value: &Value, expected_run_id: &str) -> Result Err("Codewhale sent an unsupported remote command.".to_string()), + _ => Err("codewhale sent an unsupported remote command.".to_string()), } } @@ -4591,9 +4591,9 @@ async fn public_request( let excerpt = rejection_excerpt(response).await; return Err(match excerpt { Some(reason) => { - format!("Codewhale rejected remote-control enrollment ({status}): {reason}.") + format!("codewhale rejected remote-control enrollment ({status}): {reason}.") } - None => format!("Codewhale rejected remote-control enrollment ({status})."), + None => format!("codewhale rejected remote-control enrollment ({status})."), }); } read_bounded_json(response).await @@ -7181,7 +7181,7 @@ mod tests { controller.status = Status::Connecting; event_tx .send(RemoteEvent::FailedPreLease( - "Codewhale rejected remote-control enrollment (403): client version not accepted." + "codewhale rejected remote-control enrollment (403): client version not accepted." .to_string(), )) .unwrap(); diff --git a/crates/tui/src/tools/read_media.rs b/crates/tui/src/tools/read_media.rs index c2db20f620..0cd176a030 100644 --- a/crates/tui/src/tools/read_media.rs +++ b/crates/tui/src/tools/read_media.rs @@ -347,7 +347,7 @@ pub(crate) async fn execute_read_media( }; if crate::tools::file::is_codewhale_credential_path(&file_path) { return Err(ToolError::permission_denied( - "read_media cannot read Codewhale configuration or credential-store files; use `codewhale config list` or `codewhale auth status` for safe inspection", + "read_media cannot read codewhale configuration or credential-store files; use `codewhale config list` or `codewhale auth status` for safe inspection", )); } crate::tools::file::enforce_read_denylist(&file_path, "read_media")?; @@ -1359,7 +1359,7 @@ mod tests { let err = tool.execute_rich(input, &ctx).await.unwrap_err(); assert!( err.to_string() - .contains("cannot read Codewhale configuration or credential-store"), + .contains("cannot read codewhale configuration or credential-store"), "{}", err ); @@ -1406,7 +1406,7 @@ mod tests { assert!( err_follow .to_string() - .contains("cannot read Codewhale configuration or credential-store"), + .contains("cannot read codewhale configuration or credential-store"), "follow_symlinks policy must catch canonical credential path: {}", err_follow ); diff --git a/crates/tui/src/tools/review.rs b/crates/tui/src/tools/review.rs index 5bb02ced5e..c6459cc0e1 100644 --- a/crates/tui/src/tools/review.rs +++ b/crates/tui/src/tools/review.rs @@ -29,7 +29,7 @@ const REVIEW_RECEIPT_SCHEMA_VERSION: u32 = 1; /// mechanical fix is small; anything larger is judgement wearing a /// suggestion fence, so it must degrade to prose. pub const MAX_COMMITTABLE_SUGGESTION_LINES: u32 = 25; -const REVIEW_CLIENT_UNAVAILABLE: &str = "Review tool requires an active Codewhale model client"; +const REVIEW_CLIENT_UNAVAILABLE: &str = "Review tool requires an active codewhale model client"; const REVIEW_SYSTEM_PROMPT: &str = "You are a senior code reviewer. Return ONLY valid JSON with \ the following schema:\n\ @@ -1103,7 +1103,7 @@ mod tests { assert_eq!( error, - "Failed to locate tool: Review tool requires an active Codewhale model client" + "Failed to locate tool: Review tool requires an active codewhale model client" ); assert!(!error.contains("DeepSeek")); } diff --git a/crates/tui/src/tools/shell.rs b/crates/tui/src/tools/shell.rs index 31707c3a96..84961f63df 100644 --- a/crates/tui/src/tools/shell.rs +++ b/crates/tui/src/tools/shell.rs @@ -5216,7 +5216,7 @@ impl ToolSpec for BashTool { } } else if persist && result.status == ShellStatus::Running { format!( - "Persistent service staged: {task_id_str}. Probe readiness with a separate command. Codewhale will transfer ownership only if this exec finishes successfully." + "Persistent service staged: {task_id_str}. Probe readiness with a separate command. codewhale will transfer ownership only if this exec finishes successfully." ) } else if result.status == ShellStatus::Running { let completion_contract = if context.owner_agent_id.is_some() { diff --git a/crates/tui/src/tui/keybindings.rs b/crates/tui/src/tui/keybindings.rs index 87ce6e5de0..b093c42447 100644 --- a/crates/tui/src/tui/keybindings.rs +++ b/crates/tui/src/tui/keybindings.rs @@ -596,7 +596,7 @@ mod tests { .expect("external-editor keybinding should be documented"); assert_eq!( crate::localization::tr(crate::localization::Locale::En, editor.description_id,), - "Open composer draft in external editor" + "Edit the draft externally" ); } diff --git a/crates/tui/src/tui/onboarding/trust_directory.rs b/crates/tui/src/tui/onboarding/trust_directory.rs index 438b53d630..a08ceb6295 100644 --- a/crates/tui/src/tui/onboarding/trust_directory.rs +++ b/crates/tui/src/tui/onboarding/trust_directory.rs @@ -131,7 +131,7 @@ mod tests { // states, not about where the lane happens to break them. let flat = body.split_whitespace().collect::>().join(" "); - assert!(flat.contains("Know this workspace"), "{body}"); + assert!(flat.contains("Can we trust this workspace?"), "{body}"); assert!(flat.contains("instructions and files"), "{body}"); assert!(flat.contains("prompt injection"), "{body}"); assert!(flat.contains("tools and hooks"), "{body}"); @@ -171,7 +171,7 @@ mod tests { } assert!(rail.contains("trust and continue"), "{rail}"); assert!(rail.contains("continue without trusting"), "{rail}"); - assert!(rail.contains("quit Codewhale"), "{rail}"); + assert!(rail.contains("quit codewhale"), "{rail}"); } } diff --git a/crates/tui/src/tui/phase_strip.rs b/crates/tui/src/tui/phase_strip.rs index 1f73301cb1..5423141aa7 100644 --- a/crates/tui/src/tui/phase_strip.rs +++ b/crates/tui/src/tui/phase_strip.rs @@ -332,15 +332,15 @@ mod tests { #[test] fn a_notice_sheds_whole_clauses_and_never_dangles() { - const NOTICE: &str = "Anonymous usage counts are on. Conversations and code are never collected. Change this in /settings; schema: docs/TELEMETRY.md"; + const NOTICE: &str = "Anonymous counts are on. Your conversations and code stay private. Change this in /settings; schema: docs/TELEMETRY.md"; assert_eq!(fit_notice(NOTICE, 200).as_deref(), Some(NOTICE)); assert_eq!( fit_notice(NOTICE, 80).as_deref(), - Some("Anonymous usage counts are on. Conversations and code are never collected.") + Some("Anonymous counts are on. Your conversations and code stay private.") ); assert_eq!( fit_notice(NOTICE, 40).as_deref(), - Some("Anonymous usage counts are on.") + Some("Anonymous counts are on.") ); assert_eq!(fit_notice(" ", 40), None); } diff --git a/crates/tui/src/tui/setup/mod.rs b/crates/tui/src/tui/setup/mod.rs index 920c7ac8e1..12b6a69f33 100644 --- a/crates/tui/src/tui/setup/mod.rs +++ b/crates/tui/src/tui/setup/mod.rs @@ -4046,7 +4046,7 @@ impl SetupWizardView { english_action: Option<&'static str>, ) -> Line<'static> { let hint = if self.locale == Locale::En { - let mut hint = "Enter records this setup snapshot.".to_string(); + let mut hint = "Enter records it.".to_string(); if let Some(action) = english_action { hint.push(' '); hint.push_str(action); diff --git a/crates/tui/src/tui/ui/dispatch.rs b/crates/tui/src/tui/ui/dispatch.rs index 7f6ac11f15..39a91a6a8a 100644 --- a/crates/tui/src/tui/ui/dispatch.rs +++ b/crates/tui/src/tui/ui/dispatch.rs @@ -959,10 +959,10 @@ pub(crate) fn parse_queue_send_command(input: &str) -> Option".to_string())); } let Ok(index) = raw_index.parse::() else { - return Some(Err("Index must be a positive number".to_string())); + return Some(Err("Use a positive number".to_string())); }; if index == 0 { - return Some(Err("Index must be >= 1".to_string())); + return Some(Err("Use 1 or more".to_string())); } Some(Ok(index - 1)) } diff --git a/crates/tui/src/tui/ui/event_loop.rs b/crates/tui/src/tui/ui/event_loop.rs index 2a51ab03b6..c66df9849c 100644 --- a/crates/tui/src/tui/ui/event_loop.rs +++ b/crates/tui/src/tui/ui/event_loop.rs @@ -4099,7 +4099,7 @@ pub(crate) async fn run_event_loop( Err(err) => { tracing::warn!(error = %err, "failed to restart terminal input pump"); app.push_status_toast( - "Terminal input stalled; recovery failed. Restart Codewhale if keys stop responding.", + "Terminal input stalled; recovery failed. Restart codewhale if keys stop responding.", StatusToastLevel::Error, None, ); diff --git a/crates/tui/src/tui/ui/tests.rs b/crates/tui/src/tui/ui/tests.rs index 815f5052a9..5b88aa6c64 100644 --- a/crates/tui/src/tui/ui/tests.rs +++ b/crates/tui/src/tui/ui/tests.rs @@ -5392,8 +5392,8 @@ async fn session_denied_cache_auto_deny_explains_the_cached_rejection() { assert_eq!(toast.level, StatusToastLevel::Warning); assert_eq!(toast.ttl_ms, Some(12_000)); assert!(toast.text.contains("matching request was denied earlier")); - assert!(toast.text.contains("during this Codewhale run")); - assert!(toast.text.contains("Restart Codewhale")); + assert!(toast.text.contains("during this codewhale run")); + assert!(toast.text.contains("Restart codewhale")); assert!(toast.text.contains("exec_shell")); let history_notice = app .history @@ -5419,7 +5419,7 @@ async fn session_denied_cache_auto_deny_explains_the_cached_rejection() { let rendered = render_underwater_test_app(&mut app, 40, 12); assert!(rendered.contains("Auto-denied"), "{rendered:?}"); assert!( - rendered.contains("Restart") && rendered.contains("Codewhale"), + rendered.contains("Restart") && rendered.contains("codewhale"), "{rendered:?}" ); } @@ -5670,8 +5670,8 @@ fn session_denied_notice_explains_cached_decision_and_recovery() { assert!(notice.contains("exec_shell")); assert!(notice.contains("matching request was denied earlier")); - assert!(notice.contains("during this Codewhale run")); - assert!(notice.contains("Restart Codewhale")); + assert!(notice.contains("during this codewhale run")); + assert!(notice.contains("Restart codewhale")); } #[tokio::test] @@ -5740,7 +5740,7 @@ async fn cached_denial_explanation_survives_tool_completion_and_done_render() { cell, HistoryCell::System { content } if content.contains("Auto-denied exec_shell") - && content.contains("Restart Codewhale") + && content.contains("Restart codewhale") ) }) .expect("cached denial must leave a durable recovery receipt"); @@ -5777,7 +5777,7 @@ async fn cached_denial_explanation_survives_tool_completion_and_done_render() { "cached-decision explanation disappeared after completion:\n{rendered}" ); assert!( - rendered.contains("Restart Codewhale"), + rendered.contains("Restart codewhale"), "cached-denial recovery path disappeared after completion:\n{rendered}" ); assert_eq!(