diff --git a/.gitignore b/.gitignore index 65ddcaf1c4..0e181a5604 100644 --- a/.gitignore +++ b/.gitignore @@ -36,6 +36,9 @@ blob-report/ # Node modules (pnpm workspace hoists to root) node_modules/ +# pnpm content-addressable store (local cache, not portable) +.pnpm-store/ + # Root npm lockfiles are accidental; desktop uses pnpm in /desktop. /package-lock.json diff --git a/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx b/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx index 601d57f95d..73b3e037cb 100644 --- a/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx +++ b/desktop/src/features/agents/ui/AgentInstanceEditDialog.tsx @@ -720,7 +720,7 @@ export function AgentInstanceEditDialog({ // explicitly instead of relying on the user to know the policy. if (!isManagedAgentActive(result.agent)) { const startedName = result.agent.name; - toast(`${startedName} saved while stopped.`, { + toast(`Changes saved. ${startedName} is still stopped.`, { action: { label: "Start now", onClick: () => { @@ -729,8 +729,8 @@ export function AgentInstanceEditDialog({ onError: (error) => toast.error( error instanceof Error - ? `${startedName} failed to start: ${error.message}` - : `${startedName} failed to start.`, + ? `Couldn't start ${startedName}: ${error.message}` + : `Couldn't start ${startedName}`, ), }); }, diff --git a/desktop/src/features/agents/ui/PersonaDeleteDialog.test.mjs b/desktop/src/features/agents/ui/PersonaDeleteDialog.test.mjs index a40e571486..37c938fa08 100644 --- a/desktop/src/features/agents/ui/PersonaDeleteDialog.test.mjs +++ b/desktop/src/features/agents/ui/PersonaDeleteDialog.test.mjs @@ -13,22 +13,25 @@ const persona = { displayName: "Scout" }; test("cascade delete discloses relay archival (plural)", () => { const copy = personaDeleteDescription(persona, 3); - assert.match(copy, /deletes 3 agent instances/); - assert.match(copy, /archives their identities on the relay/); + assert.match(copy, /3 agent instances are also deleted/); + assert.match(copy, /their identities archived in the community/); }); test("cascade delete discloses relay archival (singular)", () => { const copy = personaDeleteDescription(persona, 1); - assert.match(copy, /deletes 1 agent instance /); - assert.match(copy, /archives its identity on the relay/); + assert.match(copy, /1 agent instance is also deleted/); + assert.match(copy, /its identity archived in the community/); }); test("no instances → no archival claim (nothing is archived)", () => { const copy = personaDeleteDescription(persona, 0); - assert.equal(copy, "Delete Scout."); + assert.equal(copy, "Scout will be removed."); assert.doesNotMatch(copy, /archiv/i); }); test("null persona keeps the generic fallback", () => { - assert.equal(personaDeleteDescription(null, 2), "Delete this agent."); + assert.equal( + personaDeleteDescription(null, 2), + "This agent will be removed.", + ); }); diff --git a/desktop/src/features/agents/ui/PersonaDeleteDialog.tsx b/desktop/src/features/agents/ui/PersonaDeleteDialog.tsx index fd9da43751..f9c3125ae4 100644 --- a/desktop/src/features/agents/ui/PersonaDeleteDialog.tsx +++ b/desktop/src/features/agents/ui/PersonaDeleteDialog.tsx @@ -32,16 +32,16 @@ export function personaDeleteDescription( instanceCount: number, ): string { if (!persona) { - return "Delete this agent."; + return "This agent will be removed."; } if (instanceCount === 0) { - return `Delete ${persona.displayName}.`; + return `${persona.displayName} will be removed.`; } const cascade = instanceCount === 1 - ? "Also deletes 1 agent instance and archives its identity on the relay, so it no longer appears in member lists or mention suggestions." - : `Also deletes ${instanceCount} agent instances and archives their identities on the relay, so they no longer appear in member lists or mention suggestions.`; - return `Delete ${persona.displayName}. ${cascade}`; + ? "Its 1 agent instance is also deleted and its identity archived in the community, so it no longer appears in member lists or mention suggestions." + : `Its ${instanceCount} agent instances are also deleted and their identities archived in the community, so they no longer appear in member lists or mention suggestions.`; + return `${persona.displayName} will be removed. ${cascade}`; } export function PersonaDeleteDialog({ @@ -76,7 +76,7 @@ export function PersonaDeleteDialog({ type="button" variant="destructive" > - Delete + Delete agent diff --git a/desktop/src/features/agents/ui/TeamDeleteDialog.tsx b/desktop/src/features/agents/ui/TeamDeleteDialog.tsx index 383f92c4a5..03bc53980e 100644 --- a/desktop/src/features/agents/ui/TeamDeleteDialog.tsx +++ b/desktop/src/features/agents/ui/TeamDeleteDialog.tsx @@ -31,8 +31,8 @@ export function TeamDeleteDialog({ Delete team? {team - ? `Delete "${team.name}". Already-deployed agents are not affected, but this team template will no longer be available.` - : "Delete this team."} + ? `"${team.name}" will no longer be available as a template. Already-deployed agents aren't affected.` + : "This team template will no longer be available."} @@ -51,7 +51,7 @@ export function TeamDeleteDialog({ type="button" variant="destructive" > - Delete + Delete team diff --git a/desktop/src/features/agents/useOpenAgentActivity.ts b/desktop/src/features/agents/useOpenAgentActivity.ts index e8cfc0e8ff..90e2dc3286 100644 --- a/desktop/src/features/agents/useOpenAgentActivity.ts +++ b/desktop/src/features/agents/useOpenAgentActivity.ts @@ -10,7 +10,7 @@ import { getAgentWorkingState } from "./agentWorkingSignal"; import { useRelayAgentsQuery } from "./hooks"; const INACCESSIBLE_ACTIVITY_MESSAGE = - "This agent is active in a channel you haven't joined, so its activity can't be opened from here."; + "Can't open activity. It's in a channel you haven't joined."; /** * Can the viewer actually open this channel? Joined channels always; diff --git a/desktop/src/features/channel-templates/useApplyTemplate.ts b/desktop/src/features/channel-templates/useApplyTemplate.ts index 1f7d066fad..326cf15cca 100644 --- a/desktop/src/features/channel-templates/useApplyTemplate.ts +++ b/desktop/src/features/channel-templates/useApplyTemplate.ts @@ -16,6 +16,18 @@ import { useChannelTemplatesQuery } from "@/features/channel-templates/hooks"; import { setCanvas } from "@/shared/api/tauri"; import type { ChannelTemplate } from "@/shared/api/types"; +/** + * Format a list of failed agent names for a warning toast: up to three names + * are listed in full, then it falls back to "and N others" to keep the toast + * short. Mirrors the typing-indicator convention in TypingIndicatorRow. + */ +function formatFailedAgentNames(names: readonly string[]): string { + if (names.length === 1) return names[0]; + if (names.length === 2) return `${names[0]} and ${names[1]}`; + if (names.length === 3) return `${names[0]}, ${names[1]}, and ${names[2]}`; + return `${names[0]}, ${names[1]}, and ${names.length - 2} others`; +} + /** * TemplateBackend omits `config` — supply an empty object for provider backends. */ @@ -135,10 +147,9 @@ export function useApplyTemplate() { const result = await createChannelManagedAgents(channelId, inputs); if (result.failures.length > 0) { const { toast } = await import("sonner"); + const failedNames = result.failures.map((failure) => failure.name); toast.warning( - result.failures.length === 1 - ? "1 agent from the template could not be created" - : `${result.failures.length} agents from the template could not be created`, + `Couldn't add ${formatFailedAgentNames(failedNames)} from the template`, ); } await Promise.all([ diff --git a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx index a907f87245..64ac2cf6ae 100644 --- a/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx +++ b/desktop/src/features/channels/ui/AgentSessionThreadPanel.tsx @@ -246,14 +246,12 @@ export function AgentSessionThreadPanel({ try { await cancelManagedAgentTurn(agent.pubkey, channel.id); - toast.success( - `Stop signal sent to ${agent.name}. It may take a moment to respond.`, - ); + toast.success(`Stopping ${agent.name}'s turn. This may take a moment.`); } catch (error) { toast.error( error instanceof Error ? error.message - : `Failed to stop ${agent.name}'s current turn.`, + : `Couldn't stop ${agent.name}'s current turn`, ); } } diff --git a/desktop/src/features/channels/ui/MembersSidebarMemberCard.tsx b/desktop/src/features/channels/ui/MembersSidebarMemberCard.tsx index a332cb8500..50bb055700 100644 --- a/desktop/src/features/channels/ui/MembersSidebarMemberCard.tsx +++ b/desktop/src/features/channels/ui/MembersSidebarMemberCard.tsx @@ -67,7 +67,11 @@ type MembersSidebarMemberCardProps = { onManagedAgentAction: (agent: ManagedAgent) => void; onOpenProfile?: (pubkey: string) => void; onRemoveMember: (member: ChannelMember) => void; - onTimeout: (member: ChannelMember, expiresAtSecs: number) => void; + onTimeout: ( + member: ChannelMember, + expiresAtSecs: number, + durationLabel: string, + ) => void; onUnban: (member: ChannelMember) => void; onUntimeout: (member: ChannelMember) => void; onViewActivity?: (pubkey: string) => void; @@ -322,7 +326,11 @@ function MemberActionsMenu({ onEditRespondTo?: (agent: ManagedAgent) => void; onManagedAgentAction: (agent: ManagedAgent) => void; onRemoveMember: (member: ChannelMember) => void; - onTimeout: (member: ChannelMember, expiresAtSecs: number) => void; + onTimeout: ( + member: ChannelMember, + expiresAtSecs: number, + durationLabel: string, + ) => void; onUnban: (member: ChannelMember) => void; onUntimeout: (member: ChannelMember) => void; onViewActivity?: (pubkey: string) => void; @@ -459,6 +467,7 @@ function MemberActionsMenu({ onTimeout( member, Math.floor(Date.now() / 1000) + preset.seconds, + preset.label, ) } > diff --git a/desktop/src/features/channels/ui/useMembersSidebarModeration.ts b/desktop/src/features/channels/ui/useMembersSidebarModeration.ts index 04c4f1a70b..8ee2e6e408 100644 --- a/desktop/src/features/channels/ui/useMembersSidebarModeration.ts +++ b/desktop/src/features/channels/ui/useMembersSidebarModeration.ts @@ -55,7 +55,9 @@ export function useMembersSidebarModeration(open: boolean) { toast.success(success); } catch (error) { toast.error( - error instanceof Error ? error.message : "Moderation action failed", + error instanceof Error + ? error.message + : "Couldn't complete that action", ); } }, @@ -81,14 +83,14 @@ export function useMembersSidebarModeration(open: boolean) { ); const onTimeout = React.useCallback( - (member: ChannelMember, expiresAtSecs: number) => + (member: ChannelMember, expiresAtSecs: number, durationLabel: string) => void runModerationAction( () => timeoutMutation.mutateAsync({ pubkey: member.pubkey, expiresAt: expiresAtSecs, }), - "Member timed out", + `Member timed out for ${durationLabel}`, ), [timeoutMutation, runModerationAction], ); diff --git a/desktop/src/features/chat/ui/ChatHeader.tsx b/desktop/src/features/chat/ui/ChatHeader.tsx index 9ced506751..d9924a1017 100644 --- a/desktop/src/features/chat/ui/ChatHeader.tsx +++ b/desktop/src/features/chat/ui/ChatHeader.tsx @@ -108,7 +108,7 @@ export function ChatHeader({ await writeTextToClipboard(value); toast.success("Channel name copied"); } catch { - toast.error("Failed to copy channel name"); + toast.error("Couldn't copy channel name"); } } diff --git a/desktop/src/features/communities/ui/CommunityIconSettingsCard.tsx b/desktop/src/features/communities/ui/CommunityIconSettingsCard.tsx index a9fed1648e..c4323b22f6 100644 --- a/desktop/src/features/communities/ui/CommunityIconSettingsCard.tsx +++ b/desktop/src/features/communities/ui/CommunityIconSettingsCard.tsx @@ -72,7 +72,7 @@ export function CommunityIconSettingsCard({ toast.error( error instanceof Error ? error.message - : "Couldn’t update the community icon.", + : "Couldn’t update the community icon", ); } } diff --git a/desktop/src/features/communities/useNestNotifications.ts b/desktop/src/features/communities/useNestNotifications.ts index d93bb89ad2..aa617ba3cc 100644 --- a/desktop/src/features/communities/useNestNotifications.ts +++ b/desktop/src/features/communities/useNestNotifications.ts @@ -23,7 +23,7 @@ const MIGRATION_TOAST_KEY = "buzz-legacy-nest-migrated-notified"; export function useNestNotifications(): void { useEffect(() => { const unlistenReposError = listen("repos-dir-error", (event) => { - toast.error("Repos directory not applied", { + toast.error("Couldn't apply the repos directory", { description: event.payload, }); }); diff --git a/desktop/src/features/community-members/ui/CommunityMembersCard.tsx b/desktop/src/features/community-members/ui/CommunityMembersCard.tsx index fdc75f3d18..57c3b340fe 100644 --- a/desktop/src/features/community-members/ui/CommunityMembersCard.tsx +++ b/desktop/src/features/community-members/ui/CommunityMembersCard.tsx @@ -205,7 +205,7 @@ export function CommunityMembersCard({ }, onError: (error) => { toast.error( - error instanceof Error ? error.message : "Failed to change role", + error instanceof Error ? error.message : "Couldn't change role", ); }, }, diff --git a/desktop/src/features/community-members/ui/CommunityMembersSettingsCard.tsx b/desktop/src/features/community-members/ui/CommunityMembersSettingsCard.tsx index 9097f35387..aa7fe3b6ac 100644 --- a/desktop/src/features/community-members/ui/CommunityMembersSettingsCard.tsx +++ b/desktop/src/features/community-members/ui/CommunityMembersSettingsCard.tsx @@ -117,9 +117,7 @@ function RelayMemberRow({ toast.success(success); } catch (error) { toast.error( - error instanceof Error - ? error.message - : "Couldn’t update this community member.", + error instanceof Error ? error.message : "Couldn’t update membership", ); } } @@ -187,7 +185,7 @@ function RelayMemberRow({ pubkey: member.pubkey, role: "admin", }), - "Made community admin", + `Promoted ${displayName} to admin`, ) } > @@ -203,7 +201,7 @@ function RelayMemberRow({ pubkey: member.pubkey, role: "member", }), - "Made community member", + `Demoted ${displayName} to member`, ) } > @@ -219,7 +217,7 @@ function RelayMemberRow({ onClick={() => void mutateWithToast( () => removeMutation.mutateAsync(member.pubkey), - "Removed community member", + `Removed ${displayName} from the community`, ) } > diff --git a/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx b/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx index 64735a5d56..a8fdaf819e 100644 --- a/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx +++ b/desktop/src/features/community-members/ui/ConfirmRemoveDialog.tsx @@ -43,7 +43,7 @@ export function ConfirmRemoveDialog({ Remove {label}? - This will immediately revoke their access to the relay. + This will immediately revoke their access to the community. {member ? ( Delete {label}? - This will permanently delete this {label} and cannot be undone. + This will permanently delete this {label} and can't be undone. diff --git a/desktop/src/features/huddle/lib/huddleError.test.mjs b/desktop/src/features/huddle/lib/huddleError.test.mjs index ec61b83467..07242face0 100644 --- a/desktop/src/features/huddle/lib/huddleError.test.mjs +++ b/desktop/src/features/huddle/lib/huddleError.test.mjs @@ -37,10 +37,10 @@ test("preserves other string and Error messages", () => { test("uses action-specific fallback copy for unknown errors", () => { assert.equal( formatHuddleActionError({ reason: "unknown" }, "join"), - "Couldn’t join the huddle.", + "Couldn’t join the huddle", ); assert.equal( formatHuddleActionError(null, "start"), - "Couldn’t start the huddle.", + "Couldn’t start the huddle", ); }); diff --git a/desktop/src/features/huddle/lib/huddleError.ts b/desktop/src/features/huddle/lib/huddleError.ts index 7ee47b2133..5c1b0a0aa6 100644 --- a/desktop/src/features/huddle/lib/huddleError.ts +++ b/desktop/src/features/huddle/lib/huddleError.ts @@ -32,6 +32,6 @@ export function formatHuddleActionError( } return action === "join" - ? "Couldn’t join the huddle." - : "Couldn’t start the huddle."; + ? "Couldn’t join the huddle" + : "Couldn’t start the huddle"; } diff --git a/desktop/src/features/identity-archive/hooks.ts b/desktop/src/features/identity-archive/hooks.ts index 8149eff7b7..6b5bad0d09 100644 --- a/desktop/src/features/identity-archive/hooks.ts +++ b/desktop/src/features/identity-archive/hooks.ts @@ -153,10 +153,10 @@ export function useIdentityArchive( archiveMutation.mutate( { targetPubkey }, { - onSuccess: () => toast.success("Archived on this relay"), + onSuccess: () => toast.success("Archived in this community"), onError: (error) => toast.error( - `Archive failed: ${error instanceof Error ? error.message : String(error)}`, + `Couldn't archive: ${error instanceof Error ? error.message : String(error)}`, ), }, ); @@ -167,10 +167,10 @@ export function useIdentityArchive( unarchiveMutation.mutate( { targetPubkey }, { - onSuccess: () => toast.success("Unarchived on this relay"), + onSuccess: () => toast.success("Unarchived in this community"), onError: (error) => toast.error( - `Unarchive failed: ${error instanceof Error ? error.message : String(error)}`, + `Couldn't unarchive: ${error instanceof Error ? error.message : String(error)}`, ), }, ); diff --git a/desktop/src/features/local-archive/ui/LocalArchiveSettingsCard.tsx b/desktop/src/features/local-archive/ui/LocalArchiveSettingsCard.tsx index fbf8c506eb..a9e7ed94a4 100644 --- a/desktop/src/features/local-archive/ui/LocalArchiveSettingsCard.tsx +++ b/desktop/src/features/local-archive/ui/LocalArchiveSettingsCard.tsx @@ -302,10 +302,10 @@ function AddSubscriptionForm({ channels, onSaved, onCancel }: AddFormProps) { request.kinds, ); onSaved(); - toast.success("Archive subscription created."); + toast.success("Archive subscription created"); } catch (err) { toast.error( - err instanceof Error ? err.message : "Failed to create subscription.", + err instanceof Error ? err.message : "Couldn't create the subscription", ); } finally { setIsAdding(false); @@ -441,10 +441,12 @@ export function LocalArchiveSettingsCard() { try { await deleteSaveSubscription(scopeType, scopeValue); await reload(); - toast.success("Archive subscription removed."); + toast.success("Archive subscription removed"); } catch (err) { toast.error( - err instanceof Error ? err.message : "Failed to remove subscription.", + err instanceof Error + ? err.message + : "Couldn't remove the subscription", ); } finally { setDeletingKey(null); @@ -475,15 +477,15 @@ export function LocalArchiveSettingsCard() { } toast.success( checked - ? "Observer feed archive enabled." - : "Observer feed archive disabled.", + ? "Observer feed archive enabled" + : "Observer feed archive disabled", ); await reload(); } catch (err) { toast.error( err instanceof Error ? err.message - : "Failed to update observer archive.", + : "Couldn't update the observer archive", ); } finally { setObserverToggling(false); @@ -505,15 +507,15 @@ export function LocalArchiveSettingsCard() { setExplicitAgentMetricArchiveChoice(pubkey, checked); toast.success( checked - ? "Agent turn metric archive enabled." - : "Agent turn metric archive disabled.", + ? "Agent turn metric archive enabled" + : "Agent turn metric archive disabled", ); await reload(); } catch (err) { toast.error( err instanceof Error ? err.message - : "Failed to update agent metric archive.", + : "Couldn't update the agent metric archive", ); } finally { setMetricToggling(false); diff --git a/desktop/src/features/messages/hooks.ts b/desktop/src/features/messages/hooks.ts index 062b0ee40b..b357167b87 100644 --- a/desktop/src/features/messages/hooks.ts +++ b/desktop/src/features/messages/hooks.ts @@ -681,7 +681,7 @@ export function useDeleteMessageMutation(channel: Channel | null) { ); }, onError: (error) => { - toast.error(`Failed to delete message: ${error.message}`); + toast.error(`Couldn't delete message: ${error.message}`); }, }); } diff --git a/desktop/src/features/messages/ui/DraftsPanel.tsx b/desktop/src/features/messages/ui/DraftsPanel.tsx index 5a506a0a83..d019d03326 100644 --- a/desktop/src/features/messages/ui/DraftsPanel.tsx +++ b/desktop/src/features/messages/ui/DraftsPanel.tsx @@ -312,9 +312,9 @@ export function SendConfirmDialog({ > - Send message + Send message? - Are you sure you want to send this message to {destination}? + This message will be sent to {destination}. diff --git a/desktop/src/features/messages/ui/MessageActionBar.tsx b/desktop/src/features/messages/ui/MessageActionBar.tsx index ba45bc62fb..a57b0e8aa2 100644 --- a/desktop/src/features/messages/ui/MessageActionBar.tsx +++ b/desktop/src/features/messages/ui/MessageActionBar.tsx @@ -285,7 +285,7 @@ function MoreActionsMenu({ Delete message? - This will permanently delete this message and cannot be undone. + This will permanently delete this message and can't be undone. @@ -300,7 +300,7 @@ function MoreActionsMenu({ type="button" variant="destructive" > - Delete + Delete message diff --git a/desktop/src/features/messages/ui/SystemMessageRow.tsx b/desktop/src/features/messages/ui/SystemMessageRow.tsx index 4410964dd9..b1d4377e3f 100644 --- a/desktop/src/features/messages/ui/SystemMessageRow.tsx +++ b/desktop/src/features/messages/ui/SystemMessageRow.tsx @@ -522,7 +522,7 @@ function describeSystemEvent( title: membershipTitle, action: ( <> - was added by{" "} + added by{" "} {resolveDisplayLabel(payload.actor, currentPubkey, profiles)} @@ -566,7 +566,7 @@ function describeSystemEvent( title: membershipTitle, action: ( <> - was added by{" "} + added by{" "} {resolveDisplayLabel(payload.actor, currentPubkey, profiles)} @@ -584,16 +584,28 @@ function describeSystemEvent( title: actorName, action: <>removed {targetName} from the channel, }; - case "topic_changed": + case "topic_changed": { + const topic = payload.topic?.trim(); return { title: actorName, - action: <>changed the topic to “{payload.topic}”, + action: topic ? ( + <>changed the topic to “{topic}” + ) : ( + "cleared the channel topic" + ), }; - case "purpose_changed": + } + case "purpose_changed": { + const purpose = payload.purpose?.trim(); return { title: actorName, - action: <>changed the purpose to “{payload.purpose}”, + action: purpose ? ( + <>changed the purpose to “{purpose}” + ) : ( + "cleared the channel purpose" + ), }; + } case "channel_created": return { title: actorName, diff --git a/desktop/src/features/messages/ui/useMentionSendFlow.ts b/desktop/src/features/messages/ui/useMentionSendFlow.ts index 6d4e007cd4..84e2797be2 100644 --- a/desktop/src/features/messages/ui/useMentionSendFlow.ts +++ b/desktop/src/features/messages/ui/useMentionSendFlow.ts @@ -142,7 +142,7 @@ function isProviderBackedAgent(agent: ManagedAgent) { } const DM_THREAD_AGENT_MENTION_ERROR = - "Agents must already be in a DM to be mentioned in its threads. Start a new conversation that includes the agent."; + "You can only mention agents already in this DM. Start a new conversation to add them."; const DM_THREAD_MEMBERS_LOADING_ERROR = "Checking conversation members. Try again in a moment."; @@ -490,8 +490,8 @@ export function useMentionSendFlow({ if (agentReadiness.errors.length > 0) { const message = agentReadiness.errors.length === 1 - ? `Could not start agent mention: ${agentReadiness.errors[0]}` - : `Could not start agent mentions: ${agentReadiness.errors.join( + ? `Couldn't start agent mention: ${agentReadiness.errors[0]}` + : `Couldn't start agent mentions: ${agentReadiness.errors.join( "; ", )}`; setNonMemberPromptError(message); @@ -680,8 +680,8 @@ export function useMentionSendFlow({ if (personaMentionResult.errors.length > 0) { const message = personaMentionResult.errors.length === 1 - ? `Could not create agent mention: ${personaMentionResult.errors[0]}` - : `Could not create agent mentions: ${personaMentionResult.errors.join( + ? `Couldn't create agent mention: ${personaMentionResult.errors[0]}` + : `Couldn't create agent mentions: ${personaMentionResult.errors.join( "; ", )}`; setNonMemberPromptError(message); diff --git a/desktop/src/features/moderation/ui/MessageModerationMenuItems.tsx b/desktop/src/features/moderation/ui/MessageModerationMenuItems.tsx index e61f63b687..c4f89629c2 100644 --- a/desktop/src/features/moderation/ui/MessageModerationMenuItems.tsx +++ b/desktop/src/features/moderation/ui/MessageModerationMenuItems.tsx @@ -94,7 +94,9 @@ export function MessageModerationMenuItems({ toast.success(success); } catch (error) { toast.error( - error instanceof Error ? error.message : "Moderation action failed", + error instanceof Error + ? error.message + : "Couldn't complete that action", ); } }, diff --git a/desktop/src/features/moderation/ui/ReportMessageDialog.tsx b/desktop/src/features/moderation/ui/ReportMessageDialog.tsx index 1cbc71c90d..ceb8dfebd6 100644 --- a/desktop/src/features/moderation/ui/ReportMessageDialog.tsx +++ b/desktop/src/features/moderation/ui/ReportMessageDialog.tsx @@ -67,7 +67,7 @@ export function ReportMessageDialog({ toast.success("Report submitted to community moderators"); onOpenChange(false); }, - onError: () => toast.error("Failed to submit report"), + onError: () => toast.error("Couldn't submit report"), }, ); }; diff --git a/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx b/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx index ca87c76636..03a9473fcb 100644 --- a/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx +++ b/desktop/src/features/onboarding/ui/MachineOnboardingFlow.tsx @@ -91,7 +91,7 @@ export function MachineOnboardingFlow({ const replaceLostIdentity = React.useCallback(async () => { const confirmed = window.confirm( - "This will create a new identity and abandon your previous key. This cannot be undone. Continue?", + "This will create a new identity and abandon your previous key. This can't be undone. Continue?", ); if (!confirmed) return; diff --git a/desktop/src/features/onboarding/ui/OnboardingFlow.tsx b/desktop/src/features/onboarding/ui/OnboardingFlow.tsx index 01a226e3de..5c5be70063 100644 --- a/desktop/src/features/onboarding/ui/OnboardingFlow.tsx +++ b/desktop/src/features/onboarding/ui/OnboardingFlow.tsx @@ -407,7 +407,7 @@ export function OnboardingFlow({ // RelaunchRequiredScreen. No navigation needed here. const handleLostModeBack = React.useCallback(async () => { const confirmed = window.confirm( - "This will create a new identity and abandon your previous key. This cannot be undone. Continue?", + "This will create a new identity and abandon your previous key. This can't be undone. Continue?", ); if (!confirmed) { return; diff --git a/desktop/src/features/onboarding/ui/ProfileStep.tsx b/desktop/src/features/onboarding/ui/ProfileStep.tsx index 69da9b8f7c..6158c83fb2 100644 --- a/desktop/src/features/onboarding/ui/ProfileStep.tsx +++ b/desktop/src/features/onboarding/ui/ProfileStep.tsx @@ -123,7 +123,7 @@ function OnboardingRelayConnectionErrorCard({ .catch((error) => { hadActiveReconnectRef.current = false; const detail = error instanceof Error ? error.message : String(error); - toast.error(`Could not reconnect to the relay. ${detail}`); + toast.error(`Couldn't reconnect to the relay. ${detail}`); }) .finally(() => { reconnectActionPendingRef.current = false; diff --git a/desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx b/desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx index 2f750543db..e6afaa9e02 100644 --- a/desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx +++ b/desktop/src/features/profile/ui/ArchiveConfirmDialog.tsx @@ -39,7 +39,7 @@ export function ArchiveConfirmDialog({ {title} - Archiving hides {subject} from the space. + Archiving hides {subject} from the community. {/* The list + closing paragraph sit outside AlertDialogDescription on @@ -51,8 +51,8 @@ export function ArchiveConfirmDialog({
  • This only affects{" "} - this space — - not their account anywhere else + this community{" "} + — not their account anywhere else
  • You can unarchive them at any time to restore them
  • diff --git a/desktop/src/features/profile/ui/UserProfileAgentActions.tsx b/desktop/src/features/profile/ui/UserProfileAgentActions.tsx index 81db3405b2..3e2b44918b 100644 --- a/desktop/src/features/profile/ui/UserProfileAgentActions.tsx +++ b/desktop/src/features/profile/ui/UserProfileAgentActions.tsx @@ -310,7 +310,7 @@ function AgentDeleteConfirmDialog({ - Delete this agent? + Delete agent? Deleting this agent stops and removes the agent from this community. diff --git a/desktop/src/features/profile/ui/UserProfilePanel.tsx b/desktop/src/features/profile/ui/UserProfilePanel.tsx index c1f713d230..bf5e04cabc 100644 --- a/desktop/src/features/profile/ui/UserProfilePanel.tsx +++ b/desktop/src/features/profile/ui/UserProfilePanel.tsx @@ -464,14 +464,14 @@ export function UserProfilePanel({ if (created.spawnError) { toast.error(created.spawnError); } else { - toast.success(`Started ${created.agent.name}.`); + toast.success(`Started ${created.agent.name}`); } if (created.profileSyncError) { toast.warning(created.profileSyncError); } } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to start agent.", + error instanceof Error ? error.message : "Couldn’t start the agent", ); } }, [createManagedAgentForPersona, resolvedPersona]); @@ -486,14 +486,14 @@ export function UserProfilePanel({ }); toast.success( updated.startOnAppLaunch - ? `Will start ${updated.name} automatically.` - : `${updated.name} will stay manual-start only.`, + ? `Will start ${updated.name} automatically` + : `${updated.name} will stay manual-start only`, ); } catch (error) { toast.error( error instanceof Error ? error.message - : "Failed to update startup preference.", + : "Couldn’t update the startup preference", ); } }, [managedAgent, startOnLaunchMutation.mutateAsync]); @@ -505,11 +505,11 @@ export function UserProfilePanel({ const result = await deleteManagedAgentRecord(managedAgent); if (result.cancelled) return; - toast.success(`Deleted ${managedAgent.name}.`); + toast.success(`Deleted ${managedAgent.name}`); onClose(); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to delete agent.", + error instanceof Error ? error.message : "Couldn’t delete agent", ); } }, [deleteManagedAgentRecord, managedAgent, onClose]); @@ -572,18 +572,18 @@ export function UserProfilePanel({ id: resolvedPersona.id, active: false, }); - toast.success(`Removed ${resolvedPersona.displayName} from My Agents.`); + toast.success(`Removed ${resolvedPersona.displayName} from My Agents`); onClose(); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to delete agent.", + error instanceof Error ? error.message : "Couldn’t delete agent", ); } return; } if (resolvedPersona.sourceTeam) { - toast.error("This agent is managed by a team."); + toast.error("This agent is managed by a team"); return; } @@ -598,19 +598,19 @@ export function UserProfilePanel({ const handleConfirmDeletePersona = React.useCallback( async (personaToConfirm: AgentPersona) => { if (personaToConfirm.sourceTeam) { - toast.error("This agent is managed by a team."); + toast.error("This agent is managed by a team"); setPersonaToDelete(null); return; } try { await deletePersonaMutation.mutateAsync(personaToConfirm.id); - toast.success(`Deleted ${personaToConfirm.displayName}.`); + toast.success(`Deleted ${personaToConfirm.displayName}`); setPersonaToDelete(null); onClose(); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to delete agent.", + error instanceof Error ? error.message : "Couldn’t delete agent", ); } }, @@ -632,11 +632,11 @@ export function UserProfilePanel({ const handleAddedToChannel = React.useCallback( (channel: Channel, result: AttachManagedAgentToChannelResult) => { if (result.started) { - toast.success(`Added ${result.agent.name} to ${channel.name}.`); + toast.success(`Added ${result.agent.name} to ${channel.name}`); } else if (result.membershipAdded) { - toast.success(`Added ${result.agent.name} to ${channel.name}.`); + toast.success(`Added ${result.agent.name} to ${channel.name}`); } else { - toast.success(`${result.agent.name} is already in ${channel.name}.`); + toast.success(`${result.agent.name} is already in ${channel.name}`); } void managedAgentsQuery.refetch(); void relayAgentsQuery.refetch(); diff --git a/desktop/src/features/profile/ui/UserProfilePanelPersonaSubmit.ts b/desktop/src/features/profile/ui/UserProfilePanelPersonaSubmit.ts index eff9a1af10..2fc0d41c04 100644 --- a/desktop/src/features/profile/ui/UserProfilePanelPersonaSubmit.ts +++ b/desktop/src/features/profile/ui/UserProfilePanelPersonaSubmit.ts @@ -100,7 +100,7 @@ export async function submitProfilePersonaDialog({ `${result.agent.name} was updated, but profile sync failed: ${result.profileSyncError}`, ); } - toast.success(`Updated ${input.displayName}.`); + toast.success(`Updated ${input.displayName}`); } else { const persona = await createPersona(input); try { @@ -110,7 +110,7 @@ export async function submitProfilePersonaDialog({ `${persona.displayName} was created, but it did not start: ${created.spawnError}`, ); } else { - toast.success(`Created and started ${created.agent.name}.`); + toast.success(`Created and started ${created.agent.name}`); } if (created.profileSyncError) { toast.warning( @@ -120,16 +120,14 @@ export async function submitProfilePersonaDialog({ } catch (error) { toast.error( error instanceof Error - ? `${persona.displayName} was created, but the agent instance could not be created: ${error.message}` - : `${persona.displayName} was created, but the agent instance could not be created.`, + ? `${persona.displayName} was created, but the agent instance couldn't be created: ${error.message}` + : `${persona.displayName} was created, but the agent instance couldn't be created.`, ); } } onDone(); } catch (error) { - toast.error( - error instanceof Error ? error.message : "Failed to save agent.", - ); + toast.error(error instanceof Error ? error.message : "Couldn't save agent"); } } diff --git a/desktop/src/features/profile/ui/UserProfilePanelSections.tsx b/desktop/src/features/profile/ui/UserProfilePanelSections.tsx index 4514b62d95..44bb57e428 100644 --- a/desktop/src/features/profile/ui/UserProfilePanelSections.tsx +++ b/desktop/src/features/profile/ui/UserProfilePanelSections.tsx @@ -667,7 +667,7 @@ function ProfilePrimaryActions({ followToggleMutation.mutate(pubkey, { onError: (error) => toast.error( - `${isFollowing ? "Unfollow" : "Follow"} failed: ${error.message}`, + `Couldn't ${isFollowing ? "unfollow" : "follow"}: ${error.message}`, ), }); }; diff --git a/desktop/src/features/profile/ui/UserProfilePopover.tsx b/desktop/src/features/profile/ui/UserProfilePopover.tsx index f2739088a6..18aac61f94 100644 --- a/desktop/src/features/profile/ui/UserProfilePopover.tsx +++ b/desktop/src/features/profile/ui/UserProfilePopover.tsx @@ -335,9 +335,7 @@ export function UserProfilePopover({ } } catch (error) { toast.error( - error instanceof Error - ? error.message - : "Failed to open direct message.", + error instanceof Error ? error.message : "Couldn’t open direct message", ); } finally { if (isMountedRef.current) { @@ -471,7 +469,7 @@ export function UserProfilePopover({ } } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to send wave.", + error instanceof Error ? error.message : "Couldn’t send wave", ); } finally { if (isMountedRef.current) { diff --git a/desktop/src/features/profile/ui/UserProfileSnapshotExportDialog.tsx b/desktop/src/features/profile/ui/UserProfileSnapshotExportDialog.tsx index 003c12c812..9de7bff7d1 100644 --- a/desktop/src/features/profile/ui/UserProfileSnapshotExportDialog.tsx +++ b/desktop/src/features/profile/ui/UserProfileSnapshotExportDialog.tsx @@ -33,7 +33,7 @@ export function UserProfileSnapshotExportDialog({ { onSuccess: (saved) => { if (saved) { - toast.success(`Exported ${persona.displayName}.`); + toast.success(`Exported ${persona.displayName}`); onOpenChange(false); } }, @@ -41,7 +41,7 @@ export function UserProfileSnapshotExportDialog({ toast.error( error instanceof Error ? error.message - : "Failed to export agent snapshot.", + : "Couldn't export agent snapshot", ); }, }, diff --git a/desktop/src/features/profile/ui/useAgentLifecycleActions.ts b/desktop/src/features/profile/ui/useAgentLifecycleActions.ts index 62d0d3c7ad..6a64fa4ce8 100644 --- a/desktop/src/features/profile/ui/useAgentLifecycleActions.ts +++ b/desktop/src/features/profile/ui/useAgentLifecycleActions.ts @@ -37,7 +37,7 @@ export function useAgentLifecycleActions({ if (managedAgent.backend.type === "local") { clearActiveTurnsForAgentOnStop(managedAgent.pubkey); } - toast.success(result.noticeMessage ?? `Stopped ${managedAgent.name}.`); + toast.success(result.noticeMessage ?? `Stopped ${managedAgent.name}`); return; } @@ -47,12 +47,14 @@ export function useAgentLifecycleActions({ }); toast.success( managedAgent.backend.type === "provider" - ? `Deploying ${managedAgent.name}.` - : `Started ${managedAgent.name}.`, + ? `Deploying ${managedAgent.name}` + : `Started ${managedAgent.name}`, ); } catch (error) { toast.error( - error instanceof Error ? error.message : "Agent action failed.", + error instanceof Error + ? error.message + : "Couldn’t complete that action", ); } }, [ diff --git a/desktop/src/features/profile/ui/useProfileDmAction.ts b/desktop/src/features/profile/ui/useProfileDmAction.ts index 0d5811333a..0f3e4afaa9 100644 --- a/desktop/src/features/profile/ui/useProfileDmAction.ts +++ b/desktop/src/features/profile/ui/useProfileDmAction.ts @@ -32,9 +32,7 @@ export function useProfileDmAction({ } catch (error) { if (!isMountedRef.current) return; toast.error( - error instanceof Error - ? error.message - : "Failed to open direct message.", + error instanceof Error ? error.message : "Couldn't open direct message", ); setIsOpeningDm(false); return; diff --git a/desktop/src/features/projects/ui/CreateProjectIssueDialog.tsx b/desktop/src/features/projects/ui/CreateProjectIssueDialog.tsx index af28693bb4..d3c9537c03 100644 --- a/desktop/src/features/projects/ui/CreateProjectIssueDialog.tsx +++ b/desktop/src/features/projects/ui/CreateProjectIssueDialog.tsx @@ -39,7 +39,7 @@ export function CreateProjectIssueDialog({ async function handleCreate(input: CreateProjectWorkItemDialogInput) { if (!project) throw new Error("Choose a repository."); const issueId = await createMutation.mutateAsync(input); - toast.success("Issue created."); + toast.success("Issue created"); await onCreated(project, issueId); } diff --git a/desktop/src/features/projects/ui/CreatePullRequestDialog.tsx b/desktop/src/features/projects/ui/CreatePullRequestDialog.tsx index d64d132aed..11af95f1e5 100644 --- a/desktop/src/features/projects/ui/CreatePullRequestDialog.tsx +++ b/desktop/src/features/projects/ui/CreatePullRequestDialog.tsx @@ -138,7 +138,7 @@ export function CreatePullRequestDialog({ mergeBase: sourceSyncQuery.data?.mergeBase ?? null, reviewers: [], }); - toast.success("Pull request created."); + toast.success("Pull request created"); await onCreated(project, pullRequestId); } diff --git a/desktop/src/features/projects/ui/MergePullRequestButton.tsx b/desktop/src/features/projects/ui/MergePullRequestButton.tsx index 40757f1529..2b49fec6a7 100644 --- a/desktop/src/features/projects/ui/MergePullRequestButton.tsx +++ b/desktop/src/features/projects/ui/MergePullRequestButton.tsx @@ -105,9 +105,7 @@ export function MergePullRequestButton({ setConfirmOpen(false); } toast.error( - error instanceof Error - ? error.message - : "Failed to merge pull request.", + error instanceof Error ? error.message : "Failed to merge pull request", ); } }, [mergeMutation, pullRequest]); @@ -138,12 +136,12 @@ export function MergePullRequestButton({ recoveryRef: result.recoveryRef, targetRef: result.targetRef, }); - toast.success("Recovery commit fetched and terminal opened."); + toast.success("Recovery commit fetched and terminal opened"); } catch (error) { toast.error( error instanceof Error ? error.message - : "Failed to prepare merge recovery.", + : "Failed to prepare merge recovery", ); } finally { setIsPreparingRecovery(false); @@ -164,12 +162,12 @@ export function MergePullRequestButton({ statusEvent: unpublishedStatusEvent, }); setUnpublishedStatusState(null); - toast.success("Published merged pull request status."); + toast.success("Published merged pull request status"); } catch (error) { toast.error( error instanceof Error ? error.message - : "Failed to publish merged pull request status.", + : "Failed to publish merged pull request status", ); } }, [publishMergedMutation, unpublishedStatusEvent]); diff --git a/desktop/src/features/projects/ui/ProjectCards.tsx b/desktop/src/features/projects/ui/ProjectCards.tsx index 52308f7a05..5a38355287 100644 --- a/desktop/src/features/projects/ui/ProjectCards.tsx +++ b/desktop/src/features/projects/ui/ProjectCards.tsx @@ -363,7 +363,7 @@ function ProjectActionsMenu({ Delete project? Delete {project.name} from Projects for everyone. This can only be - done for projects you own and cannot be undone. + done for projects you own and can't be undone. diff --git a/desktop/src/features/projects/ui/ProjectDetailScreen.tsx b/desktop/src/features/projects/ui/ProjectDetailScreen.tsx index 587dd0d11b..d876b2d7ee 100644 --- a/desktop/src/features/projects/ui/ProjectDetailScreen.tsx +++ b/desktop/src/features/projects/ui/ProjectDetailScreen.tsx @@ -339,13 +339,13 @@ export function ProjectDetailScreen(props: ProjectDetailScreenProps) { ]); const error = results.find((result) => result.error)?.error; if (error) { - toast.error("Could not fetch repository.", { + toast.error("Couldn't fetch repository", { description: error instanceof Error ? error.message : "The Git fetch failed.", }); return; } - toast.success("Remote state refreshed."); + toast.success("Remote state refreshed"); }, [repoSnapshotQuery, repoStateQuery, repoSyncStatusQuery]); // Compact branch + remote/local controls shared by the readme and Files // tab headers. @@ -585,7 +585,7 @@ export function ProjectDetailScreen(props: ProjectDetailScreenProps) { const handleCreateIssue = React.useCallback( async ({ body, title }: CreateIssueDialogInput) => { const issueId = await createIssueMutation.mutateAsync({ body, title }); - toast.success("Issue created."); + toast.success("Issue created"); await issuesQuery.refetch(); setSelectedIssueId(issueId); }, @@ -600,7 +600,7 @@ export function ProjectDetailScreen(props: ProjectDetailScreenProps) { mergeBase: repoSyncStatusQuery.data?.mergeBase ?? null, }); toast.success( - updated ? "Pull request updated." : "Pull request is already current.", + updated ? "Pull request updated" : "Pull request is already current", ); await pullRequestsQuery.refetch(); } catch (error) { diff --git a/desktop/src/features/projects/ui/ProjectIssuesPanel.tsx b/desktop/src/features/projects/ui/ProjectIssuesPanel.tsx index 104000e553..e359cecdcf 100644 --- a/desktop/src/features/projects/ui/ProjectIssuesPanel.tsx +++ b/desktop/src/features/projects/ui/ProjectIssuesPanel.tsx @@ -190,10 +190,10 @@ export function ProjectIssueDetail({ mediaTags, mentionPubkeys, }); - toast.success("Comment posted."); + toast.success("Comment posted"); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to post comment.", + error instanceof Error ? error.message : "Failed to post comment", ); throw error; } diff --git a/desktop/src/features/projects/ui/ProjectPullRequestFilesChangedPanel.tsx b/desktop/src/features/projects/ui/ProjectPullRequestFilesChangedPanel.tsx index c257457d31..8591a3c17d 100644 --- a/desktop/src/features/projects/ui/ProjectPullRequestFilesChangedPanel.tsx +++ b/desktop/src/features/projects/ui/ProjectPullRequestFilesChangedPanel.tsx @@ -702,14 +702,14 @@ export function ProjectPullRequestFilesChangedPanel({ setActiveAnchor(null); toast.success( decision === "request-changes" - ? "Changes requested." - : "Line comment posted.", + ? "Changes requested" + : "Line comment posted", ); } catch (error) { toast.error( error instanceof Error ? error.message - : "Failed to post line comment.", + : "Failed to post line comment", ); throw error; } diff --git a/desktop/src/features/projects/ui/ProjectPullRequestsPanel.tsx b/desktop/src/features/projects/ui/ProjectPullRequestsPanel.tsx index c93691a924..e9e5365f97 100644 --- a/desktop/src/features/projects/ui/ProjectPullRequestsPanel.tsx +++ b/desktop/src/features/projects/ui/ProjectPullRequestsPanel.tsx @@ -546,12 +546,12 @@ export function ProjectPullRequestDetail({ }); toast.success( decision === "request-changes" - ? "Changes requested." - : "Comment posted.", + ? "Changes requested" + : "Comment posted", ); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to post comment.", + error instanceof Error ? error.message : "Failed to post comment", ); throw error; } diff --git a/desktop/src/features/projects/ui/ProjectsAgentPromptPage.tsx b/desktop/src/features/projects/ui/ProjectsAgentPromptPage.tsx index 29705425f6..be4502868a 100644 --- a/desktop/src/features/projects/ui/ProjectsAgentPromptPage.tsx +++ b/desktop/src/features/projects/ui/ProjectsAgentPromptPage.tsx @@ -397,7 +397,7 @@ export function ProjectsAgentPromptPage({ richText.clearContent(); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to reach the agent", + error instanceof Error ? error.message : "Couldn't reach agent", ); } finally { setIsSending(false); diff --git a/desktop/src/features/projects/ui/ProjectsView.tsx b/desktop/src/features/projects/ui/ProjectsView.tsx index 2f22bfe0c1..ff4afba191 100644 --- a/desktop/src/features/projects/ui/ProjectsView.tsx +++ b/desktop/src/features/projects/ui/ProjectsView.tsx @@ -603,7 +603,7 @@ export function ProjectsView() { isCreating={createProjectMutation.isPending} onCreate={async (input) => { const project = await createProjectMutation.mutateAsync(input); - toast.success(`Project "${project.name}" created.`); + toast.success(`Project "${project.name}" created`); // Land on the list that actually shows the new project — the // Overview only surfaces the top few most-active repositories. handleRepositoryScopeChange("all"); diff --git a/desktop/src/features/projects/ui/PullRequestReviewCard.tsx b/desktop/src/features/projects/ui/PullRequestReviewCard.tsx index c903769b7d..fb46067686 100644 --- a/desktop/src/features/projects/ui/PullRequestReviewCard.tsx +++ b/desktop/src/features/projects/ui/PullRequestReviewCard.tsx @@ -90,16 +90,16 @@ export function PullRequestReviewCard({ }); toast.success( status === "draft" - ? "Converted to draft." + ? "Converted to draft" : status === "closed" - ? "Pull request closed." + ? "Pull request closed" : pullRequest.status === "Closed" - ? "Pull request reopened." - : "Marked as ready for review.", + ? "Pull request reopened" + : "Marked as ready for review", ); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to update status.", + error instanceof Error ? error.message : "Failed to update status", ); } }, @@ -147,8 +147,8 @@ export function PullRequestReviewCard({ const handleApprove = React.useCallback(async () => { const approved = await runReviewDecision( approvePullRequest, - "Pull request approved.", - "Failed to approve.", + "Pull request approved", + "Failed to approve", approvalSummary, ); if (approved) { diff --git a/desktop/src/features/projects/ui/PullRequestReviewersRow.tsx b/desktop/src/features/projects/ui/PullRequestReviewersRow.tsx index 3c0caa9193..49e3008d7d 100644 --- a/desktop/src/features/projects/ui/PullRequestReviewersRow.tsx +++ b/desktop/src/features/projects/ui/PullRequestReviewersRow.tsx @@ -113,10 +113,10 @@ export function PullRequestReviewersRow({ }); setPickerOpen(false); setReviewerQuery(""); - toast.success("Review requested."); + toast.success("Review requested"); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to request review.", + error instanceof Error ? error.message : "Failed to request review", ); } finally { requestInFlightRef.current = false; diff --git a/desktop/src/features/projects/ui/useOpenProjectTerminal.ts b/desktop/src/features/projects/ui/useOpenProjectTerminal.ts index 64d2415536..6defabed6a 100644 --- a/desktop/src/features/projects/ui/useOpenProjectTerminal.ts +++ b/desktop/src/features/projects/ui/useOpenProjectTerminal.ts @@ -43,7 +43,7 @@ export function useOpenProjectTerminal(reposDir?: string | null) { } } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to open terminal", + error instanceof Error ? error.message : "Couldn't open the terminal", { id: toastId }, ); } diff --git a/desktop/src/features/pulse/lib/useNoteActions.ts b/desktop/src/features/pulse/lib/useNoteActions.ts index 8178cdc53a..a88bf67234 100644 --- a/desktop/src/features/pulse/lib/useNoteActions.ts +++ b/desktop/src/features/pulse/lib/useNoteActions.ts @@ -98,7 +98,7 @@ export function usePulseNoteActions({ queryClient.setQueryData(reactionQueryKey, previousReactions); toast.error( - error instanceof Error ? error.message : "Failed to update reaction", + error instanceof Error ? error.message : "Couldn't update reaction", ); } finally { setPendingUpvoteNoteIds((current) => @@ -135,7 +135,7 @@ export function usePulseNoteActions({ }); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to post reply", + error instanceof Error ? error.message : "Couldn't post reply", ); throw error; } @@ -148,7 +148,7 @@ export function usePulseNoteActions({ await writeTextToClipboard(buildNoteShareUri(note)); toast.success("Copied note link"); } catch { - toast.error("Failed to copy note link"); + toast.error("Couldn't copy note link"); } }, []); @@ -164,7 +164,7 @@ export function usePulseNoteActions({ }); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to open DM", + error instanceof Error ? error.message : "Couldn't open DM", ); } }, diff --git a/desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx b/desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx index 2833eee45f..bcdc936eba 100644 --- a/desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx +++ b/desktop/src/features/reminders/ui/RemindMeLaterDialog.tsx @@ -48,7 +48,7 @@ export function RemindMeLaterDialog({ onOpenChange(false); setNote(""); }, - onError: () => toast.error("Failed to create reminder"), + onError: () => toast.error("Couldn't create reminder"), }, ); }; diff --git a/desktop/src/features/reminders/ui/RemindersPanel.tsx b/desktop/src/features/reminders/ui/RemindersPanel.tsx index 651768a251..630971cb1f 100644 --- a/desktop/src/features/reminders/ui/RemindersPanel.tsx +++ b/desktop/src/features/reminders/ui/RemindersPanel.tsx @@ -72,7 +72,7 @@ function ReminderRow({ const handleComplete = () => { complete.mutate(reminder, { onSuccess: () => toast.success("Reminder completed"), - onError: () => toast.error("Failed to complete reminder"), + onError: () => toast.error("Couldn't complete reminder"), }); }; @@ -81,7 +81,7 @@ function ReminderRow({ { reminder, notBefore }, { onSuccess: () => toast.success("Reminder snoozed"), - onError: () => toast.error("Failed to snooze reminder"), + onError: () => toast.error("Couldn't snooze reminder"), }, ); }; @@ -89,7 +89,7 @@ function ReminderRow({ const handleCancel = () => { cancel.mutate(reminder, { onSuccess: () => toast.success("Reminder cancelled"), - onError: () => toast.error("Failed to cancel reminder"), + onError: () => toast.error("Couldn't cancel reminder"), }); }; diff --git a/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx b/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx index 82680ae5a8..1a0fb9d9f5 100644 --- a/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx +++ b/desktop/src/features/settings/ui/ChannelTemplatesSettingsCard.tsx @@ -78,7 +78,7 @@ export function ChannelTemplatesSettingsCard() { }, onError: (error) => { toast.error( - error instanceof Error ? error.message : "Failed to duplicate", + error instanceof Error ? error.message : "Couldn't duplicate", ); }, }); @@ -92,9 +92,7 @@ export function ChannelTemplatesSettingsCard() { setDeleteTarget(null); }, onError: (error) => { - toast.error( - error instanceof Error ? error.message : "Failed to delete", - ); + toast.error(error instanceof Error ? error.message : "Couldn't delete"); }, }); } @@ -168,10 +166,10 @@ export function ChannelTemplatesSettingsCard() { > - Delete template + Delete template? - Are you sure you want to delete "{deleteTarget?.name}"? - This action cannot be undone. + Delete "{deleteTarget?.name}". This can't be + undone. @@ -180,7 +178,7 @@ export function ChannelTemplatesSettingsCard() { className="bg-destructive text-destructive-foreground hover:bg-destructive/90" onClick={handleDelete} > - Delete + Delete template @@ -375,7 +373,7 @@ function TemplateFormDialog({ }, onError: (error) => { toast.error( - error instanceof Error ? error.message : "Failed to update", + error instanceof Error ? error.message : "Couldn't update", ); }, }); @@ -394,7 +392,7 @@ function TemplateFormDialog({ }, onError: (error) => { toast.error( - error instanceof Error ? error.message : "Failed to create", + error instanceof Error ? error.message : "Couldn't create", ); }, }); diff --git a/desktop/src/features/settings/ui/ModerationQueueCard.tsx b/desktop/src/features/settings/ui/ModerationQueueCard.tsx index ca9adf980d..6e3cdd7668 100644 --- a/desktop/src/features/settings/ui/ModerationQueueCard.tsx +++ b/desktop/src/features/settings/ui/ModerationQueueCard.tsx @@ -414,7 +414,7 @@ function QueueTab() { ); } catch (error) { toast.error( - error instanceof Error ? error.message : "Failed to resolve the report", + error instanceof Error ? error.message : "Couldn't resolve the report", ); } } diff --git a/desktop/src/features/settings/ui/SignOutSection.tsx b/desktop/src/features/settings/ui/SignOutSection.tsx index 8d4dc1c481..dc093c13eb 100644 --- a/desktop/src/features/settings/ui/SignOutSection.tsx +++ b/desktop/src/features/settings/ui/SignOutSection.tsx @@ -123,7 +123,7 @@ export function SignOutSection() { setIsPending(false); setIsOpen(false); resetDialogState(); - toast.error(err instanceof Error ? err.message : "Sign out failed."); + toast.error(err instanceof Error ? err.message : "Couldn’t sign out"); }); } @@ -137,7 +137,7 @@ export function SignOutSection() {

    Sign out

    Removes your identity key and all local app data from this device. - Back up your private key (nsec) first — this cannot be undone. + Back up your private key (nsec) first — this can't be undone.

    This will delete your identity key, all agent settings, and cached data from this device, then relaunch Buzz into first-run setup. - This cannot be undone. + This can't be undone. @@ -257,7 +257,7 @@ export function SignOutSection() { className="h-4 w-4 border-2" /> ) : null} - {isPending ? "Signing out…" : "Delete My Data"} + {isPending ? "Signing out…" : "Delete my data"}
    diff --git a/desktop/src/features/sidebar/ui/ChannelSectionDialogs.tsx b/desktop/src/features/sidebar/ui/ChannelSectionDialogs.tsx index 6b054fa600..78c2578c76 100644 --- a/desktop/src/features/sidebar/ui/ChannelSectionDialogs.tsx +++ b/desktop/src/features/sidebar/ui/ChannelSectionDialogs.tsx @@ -249,14 +249,14 @@ export function DeleteSectionAlertDialog({ channelCount === 1 ? "1 channel" : `${channelCount} channels`; const description = channelCount === 0 - ? `Delete section "${sectionName}"? It has no channels.` - : `Delete section "${sectionName}"? Its ${channelLabel} will move back to the default Channels group.`; + ? `"${sectionName}" has no channels.` + : `Its ${channelLabel} will move back to the default Channels group.`; return ( - Delete section + Delete section? {description} @@ -265,7 +265,7 @@ export function DeleteSectionAlertDialog({ className="bg-destructive text-destructive-foreground hover:bg-destructive/90" onClick={onConfirm} > - Delete + Delete section @@ -294,9 +294,9 @@ export function LeaveChannelAlertDialog({ - Leave channel + Leave channel? - {`Leave "${channelName}"? You'll stop receiving its messages and can rejoin later.`} + {`You'll stop receiving messages from "${channelName}" and can rejoin later.`} diff --git a/desktop/src/features/workflows/ui/WorkflowDeleteDialog.tsx b/desktop/src/features/workflows/ui/WorkflowDeleteDialog.tsx index db07470f2c..423071977b 100644 --- a/desktop/src/features/workflows/ui/WorkflowDeleteDialog.tsx +++ b/desktop/src/features/workflows/ui/WorkflowDeleteDialog.tsx @@ -31,8 +31,8 @@ export function WorkflowDeleteDialog({ Delete workflow? {workflow - ? `Delete "${workflow.name}". This will stop all future triggers and remove the workflow permanently.` - : "Delete this workflow."} + ? `"${workflow.name}" will stop triggering and be removed permanently.` + : "This workflow will be removed permanently."} @@ -51,7 +51,7 @@ export function WorkflowDeleteDialog({ type="button" variant="destructive" > - Delete + Delete workflow diff --git a/desktop/src/shared/lib/clipboard.ts b/desktop/src/shared/lib/clipboard.ts index 93e2bed44e..25a06fa259 100644 --- a/desktop/src/shared/lib/clipboard.ts +++ b/desktop/src/shared/lib/clipboard.ts @@ -17,6 +17,6 @@ export function copyTextToClipboard( toast.success(successMessage); }) .catch(() => { - toast.error("Failed to copy to clipboard"); + toast.error("Couldn't copy to clipboard"); }); } diff --git a/desktop/src/shared/lib/localStorageQuota.ts b/desktop/src/shared/lib/localStorageQuota.ts index bf194a6cc8..39dab9f1a5 100644 --- a/desktop/src/shared/lib/localStorageQuota.ts +++ b/desktop/src/shared/lib/localStorageQuota.ts @@ -38,9 +38,9 @@ function notifyStorageFull(): void { // Dynamic import keeps this module usable from node unit tests. import("sonner") .then(({ toast }) => { - toast.error("Local storage is full", { + toast.error("Storage is full", { description: - "Buzz could not save some local data — read positions may not persist across restarts.", + "Buzz couldn't save some data. Recent changes may be lost when you restart.", }); }) .catch(() => {}); diff --git a/desktop/src/shared/ui/markdown.tsx b/desktop/src/shared/ui/markdown.tsx index b1f9623f3e..6afe400ea6 100644 --- a/desktop/src/shared/ui/markdown.tsx +++ b/desktop/src/shared/ui/markdown.tsx @@ -1165,7 +1165,7 @@ function ImageBlock({ alt, dim, resolvedSrc, src, thumbSrc }: ImageBlockProps) { toast.success("Copied to clipboard"); }) .catch((err: unknown) => { - const msg = err instanceof Error ? err.message : "Copy failed"; + const msg = err instanceof Error ? err.message : "Couldn't copy"; toast.error(msg); }); }, []); @@ -1176,7 +1176,7 @@ function ImageBlock({ alt, dim, resolvedSrc, src, thumbSrc }: ImageBlockProps) { if (!downloadSrc) return; invokeTauri("download_image", { url: downloadSrc }).catch( (err: unknown) => { - const msg = err instanceof Error ? err.message : "Download failed"; + const msg = err instanceof Error ? err.message : "Couldn't download"; toast.error(msg); }, ); @@ -1332,7 +1332,7 @@ function ExternalLinkAnchor({ onSelect: () => { closeMenu(); void openUrl(href).catch(() => { - toast.error("Failed to open link"); + toast.error("Couldn't open link"); }); }, }, diff --git a/desktop/src/shared/ui/markdown/CodeBlock.tsx b/desktop/src/shared/ui/markdown/CodeBlock.tsx index 06f9fb4c4b..faa3777d61 100644 --- a/desktop/src/shared/ui/markdown/CodeBlock.tsx +++ b/desktop/src/shared/ui/markdown/CodeBlock.tsx @@ -87,7 +87,7 @@ export function MarkdownCodeBlock({ toast.success("Copied code to clipboard"); } catch (error) { console.error("Failed to copy code block", error); - toast.error("Failed to copy code"); + toast.error("Couldn't copy code"); } finally { setIsCopying(false); } diff --git a/desktop/src/shared/ui/markdown/FileCard.tsx b/desktop/src/shared/ui/markdown/FileCard.tsx index 889847193e..4015662e34 100644 --- a/desktop/src/shared/ui/markdown/FileCard.tsx +++ b/desktop/src/shared/ui/markdown/FileCard.tsx @@ -49,7 +49,8 @@ export function FileCard({ onClick={() => { invokeTauri("download_file", { url: href, filename }).catch( (err: unknown) => { - const msg = err instanceof Error ? err.message : "Download failed"; + const msg = + err instanceof Error ? err.message : "Couldn't download"; toast.error(msg); }, ); diff --git a/desktop/src/shared/ui/useVideoContextMenu.tsx b/desktop/src/shared/ui/useVideoContextMenu.tsx index ec6c5791f7..91f1998dd7 100644 --- a/desktop/src/shared/ui/useVideoContextMenu.tsx +++ b/desktop/src/shared/ui/useVideoContextMenu.tsx @@ -55,7 +55,9 @@ export function useVideoContextMenu( url: downloadUrl, filename: resolveVideoDownloadFilename(filename), }).catch((err: unknown) => { - toast.error(err instanceof Error ? err.message : "Download failed"); + toast.error( + err instanceof Error ? err.message : "Couldn't download", + ); }); }, }); diff --git a/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts b/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts index de94bb230f..31d497db2b 100644 --- a/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts +++ b/desktop/tests/e2e/agent-lifecycle-feedback.spec.ts @@ -1,8 +1,8 @@ /** * E2E screenshots + regression tests for agent-lifecycle feedback (PR #1766): * - * 1. Persona delete confirm dialog shows "Also deletes N agent instance(s)." - * when the persona has linked managed-agent instances. + * 1. Persona delete confirm dialog discloses that N linked agent instance(s) + * are also deleted when the persona has linked managed-agent instances. * 2. Global-config save reports "Saved. Restarted N agents." when running agents * were restarted. * 3. Global-config save reports plain "Saved." when no agents were restarted; @@ -75,7 +75,7 @@ test.describe("agent lifecycle feedback screenshots", () => { }); }); - // Shot 01: persona delete confirm dialog — "Also deletes 2 agent instance(s)." + // Shot 01: persona delete confirm dialog — 2 linked agent instances. // Seeds a custom persona with two linked managed agents so instanceCount = 2. // Triggers the delete confirm from the persona's "..." actions menu. test("01-delete-cascade-copy", async ({ page }) => { @@ -124,9 +124,9 @@ test.describe("agent lifecycle feedback screenshots", () => { await expect(dialog).toBeVisible({ timeout: 5_000 }); // Core assertion: the cascade copy shows the correct instance count - // (plural) and discloses the relay-side archival (PR #2135). + // (plural) and discloses the identity archival (PR #2135). await expect(dialog).toContainText( - "Also deletes 2 agent instances and archives their identities on the relay", + "Its 2 agent instances are also deleted and their identities archived in the community", ); await waitForAnimations(page); @@ -215,7 +215,7 @@ test.describe("agent lifecycle feedback screenshots", () => { }); }); - // Shot 04: persona delete confirm dialog — singular "Also deletes 1 agent instance." + // Shot 04: persona delete confirm dialog — singular 1 linked agent instance. // One linked instance → singular copy (no extra "s"). test("04-delete-cascade-singular", async ({ page }) => { await installMockBridge(page, { @@ -253,7 +253,7 @@ test.describe("agent lifecycle feedback screenshots", () => { // Singular copy ("instance", "its identity") plus the archival disclosure. await expect(dialog).toContainText( - "Also deletes 1 agent instance and archives its identity on the relay", + "Its 1 agent instance is also deleted and its identity archived in the community", ); await waitForAnimations(page); @@ -263,7 +263,7 @@ test.describe("agent lifecycle feedback screenshots", () => { }); // Shot 05: persona delete confirm dialog — zero linked instances. - // No managed agents linked to the persona → "Also deletes…" line absent. + // No managed agents linked to the persona → cascade line absent. test("05-delete-cascade-zero-instances", async ({ page }) => { await installMockBridge(page, { personas: [ @@ -292,7 +292,7 @@ test.describe("agent lifecycle feedback screenshots", () => { await expect(dialog).toBeVisible({ timeout: 5_000 }); // No linked instances → no cascade warning. - await expect(dialog).not.toContainText("Also deletes"); + await expect(dialog).not.toContainText("agent instance"); }); // Shot 06: global config save — singular "Saved. Restarted 1 agent."