Merge origin/main into deferred OpenCode restart branch.

Adopt main's providerAuth helpers (OAuth index preservation, OAuth-only API
key hiding, always-load auth methods) while keeping deferred Apply & Restart
for provider mutations.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
Cursor Agent
2026-08-04 13:29:46 +00:00
co-authored by Serhii Dziupin
133 changed files with 6361 additions and 714 deletions
@@ -2,6 +2,7 @@ import React from 'react';
import type { Session } from '@opencode-ai/sdk/v2';
import { Icon } from '@/components/icon/Icon';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { toast } from '@/components/ui';
import { cn, formatDirectoryName } from '@/lib/utils';
import { useI18n } from '@/lib/i18n';
import { sessionEvents } from '@/lib/sessionEvents';
@@ -28,6 +29,7 @@ export function ArchiveView(): React.ReactNode {
const setOpen = useUIStore((state) => state.setArchivePageOpen);
const setActiveMainTab = useUIStore((state) => state.setActiveMainTab);
const setCurrentSession = useSessionUIStore((state) => state.setCurrentSession);
const unarchiveSession = useSessionUIStore((state) => state.unarchiveSession);
const homeDirectory = useDirectoryStore((state) => state.homeDirectory);
const archivedSessions = useGlobalSessionsStore(useShallow((state) => open ? state.archivedSessions : []));
const [query, setQuery] = React.useState('');
@@ -87,6 +89,16 @@ export function ArchiveView(): React.ReactNode {
setOpen(false);
}, [setActiveMainTab, setCurrentSession, setOpen]);
const restoreSession = React.useCallback((session: Session) => {
void unarchiveSession(session.id).then((success) => {
if (success) {
toast.success(t('sessions.sidebar.session.restore.success'));
} else {
toast.error(t('sessions.sidebar.session.restore.error'));
}
});
}, [t, unarchiveSession]);
if (!open) return null;
const renderDirectoryItem = (
@@ -196,7 +208,7 @@ export function ArchiveView(): React.ReactNode {
return (
<div
key={session.id}
className="group relative flex cursor-pointer items-center gap-3 rounded-md py-1 pl-2 pr-2 transition-[padding] hover:bg-interactive-hover/40 hover:pr-8 focus-within:pr-8"
className="group relative flex cursor-pointer items-center gap-3 rounded-md py-1 pl-2 pr-2 transition-[padding] hover:bg-interactive-hover/40 hover:pr-14 focus-within:pr-14"
onClick={() => openSession(session)}
role="button"
tabIndex={0}
@@ -218,6 +230,17 @@ export function ArchiveView(): React.ReactNode {
<span className="flex-shrink-0 text-[0.72rem] text-muted-foreground/75">
{formatSessionDateLabel(session.time?.archived ?? session.time?.updated ?? session.time?.created ?? Date.now())}
</span>
<button
type="button"
onClick={(event) => {
event.stopPropagation();
restoreSession(session);
}}
className="absolute right-7 top-1/2 inline-flex h-6 w-6 -translate-y-1/2 items-center justify-center rounded-md text-muted-foreground opacity-0 transition-opacity pointer-events-none hover:text-foreground group-hover:opacity-100 group-hover:pointer-events-auto focus-visible:opacity-100 focus-visible:pointer-events-auto focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/50"
aria-label={t('sessions.archivePage.restoreSessionAria', { title: session.title || t('sessions.sidebar.session.untitled') })}
>
<Icon name="inbox-unarchive" className="h-3.5 w-3.5" />
</button>
<button
type="button"
onClick={(event) => {
+13 -6
View File
@@ -70,7 +70,7 @@ import { Icon } from "@/components/icon/Icon";
import { useMessageTTS } from '@/hooks/useMessageTTS';
import { ensurePierreThemeRegistered } from '@/lib/shiki/appThemeRegistry';
import { getDefaultTheme } from '@/lib/theme/themes';
import { openDesktopFileInApp, openDesktopPath } from '@/lib/desktop';
import { isBrowserClientRuntime, openDesktopFileInApp, openDesktopPath } from '@/lib/desktop';
import { useOpenInAppsStore } from '@/stores/useOpenInAppsStore';
import { eventMatchesShortcut, getEffectiveShortcutCombo } from '@/lib/shortcuts';
import { useI18n } from '@/lib/i18n';
@@ -361,6 +361,7 @@ interface FileRowProps {
isExpanded: boolean;
isActive: boolean;
isMobile: boolean;
isBrowserClient: boolean;
alwaysShowActions: boolean;
status?: FileStatus | null;
badge?: { modified: number; added: number } | null;
@@ -388,6 +389,7 @@ const FileRow: React.FC<FileRowProps> = ({
isExpanded,
isActive,
isMobile,
isBrowserClient,
alwaysShowActions,
status,
badge,
@@ -405,14 +407,17 @@ const FileRow: React.FC<FileRowProps> = ({
const { t } = useI18n();
const isDir = node.type === 'directory';
const { canRename, canCreateFile, canCreateFolder, canDelete, canReveal } = permissions;
const canDownload = !isDir && Boolean(downloadFile);
const canRevealPath = canReveal && !isBrowserClient;
const hasMenuActions = canRename || canCreateFile || canCreateFolder || canDelete || canDownload || canRevealPath;
const handleContextMenu = React.useCallback((event?: React.MouseEvent) => {
if (!canRename && !canCreateFile && !canCreateFolder && !canDelete && !canReveal) {
if (!hasMenuActions) {
return;
}
event?.preventDefault();
setRightClickMenuPath(node.path);
}, [canRename, canCreateFile, canCreateFolder, canDelete, canReveal, node.path, setRightClickMenuPath]);
}, [hasMenuActions, node.path, setRightClickMenuPath]);
const handleInteraction = React.useCallback(() => {
if (isDir) {
@@ -474,10 +479,10 @@ const FileRow: React.FC<FileRowProps> = ({
toast.error(t('sidebarFilesTree.toast.operationFailed'));
});
}}>
<Icon name="download" className="mr-2 size-4" /> {t('sidebarFilesTree.menu.save')}
<Icon name="download" className="mr-2 size-4" /> {t(isBrowserClient ? 'sidebarFilesTree.menu.download' : 'sidebarFilesTree.menu.save')}
</Item>
)}
{canReveal && (
{canRevealPath && (
<Item onClick={(e: React.MouseEvent) => { e.stopPropagation(); onRevealPath(node.path); }}>
<Icon name="folder-received" className="mr-2 size-4" /> {t(getRevealLabelKey())}
</Item>
@@ -546,7 +551,7 @@ const FileRow: React.FC<FileRowProps> = ({
</span>
)}
</button>
{(canRename || canCreateFile || canCreateFolder || canDelete || canReveal) && (
{hasMenuActions && (
<div className={cn(
"absolute right-1 top-1/2 -translate-y-1/2",
alwaysShowActions ? "opacity-100" : "opacity-0 focus-within:opacity-100 group-hover:opacity-100"
@@ -720,6 +725,7 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
const { files, runtime } = useRuntimeAPIs();
const { currentTheme, availableThemes, lightThemeId, darkThemeId } = useThemeSystem();
const { isMobile, isTablet, screenWidth } = useDeviceInfo();
const isBrowserClient = isBrowserClientRuntime(runtime.platform);
const alwaysShowActions = isMobile || isTablet;
const showHidden = useDirectoryShowHidden();
const showGitignored = useFilesViewShowGitignored();
@@ -2302,6 +2308,7 @@ export const FilesView: React.FC<FilesViewProps> = ({ mode = 'full' }) => {
isExpanded={isExpanded}
isActive={isActive}
isMobile={isMobile}
isBrowserClient={isBrowserClient}
alwaysShowActions={alwaysShowActions}
status={!isDir ? getFileStatus(node.path) : undefined}
badge={isDir ? getFolderBadge(node.path) : undefined}