From 90fe3c91070c924c55c049424a91aa3558358e82 Mon Sep 17 00:00:00 2001 From: 777genius Date: Thu, 28 May 2026 23:55:28 +0300 Subject: [PATCH] fix(opencode): detect managed node_modules symlink permission failures MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Распознаём отдельную диагностику для EPERM на создании managed node_modules symlink под Windows и подсказываем пользователю запустить приложение от имени Administrator. UI-подсказка и provisioning hint показываются только для этого случая, обычный Windows access-denied flow не затрагивается. --- .../ui/RuntimeProviderManagementPanelView.tsx | 24 +++++++++++ .../ProvisioningProviderStatusList.test.ts | 17 +++++++- .../ProvisioningProviderStatusList.tsx | 19 +++++++++ .../openCodeWindowsAccessDenied.test.ts | 16 ++++++++ .../utils/openCodeWindowsAccessDenied.ts | 23 +++++++++++ .../TeamProvisioningServicePrepare.test.ts | 41 ++++++++++++++++++- .../providerPrepareDiagnostics.test.ts | 38 +++++++++++++++++ ...RuntimeProviderManagementPanelView.test.ts | 39 ++++++++++++++++++ 8 files changed, 215 insertions(+), 2 deletions(-) diff --git a/src/features/runtime-provider-management/renderer/ui/RuntimeProviderManagementPanelView.tsx b/src/features/runtime-provider-management/renderer/ui/RuntimeProviderManagementPanelView.tsx index 6b098ed0..c01e5242 100644 --- a/src/features/runtime-provider-management/renderer/ui/RuntimeProviderManagementPanelView.tsx +++ b/src/features/runtime-provider-management/renderer/ui/RuntimeProviderManagementPanelView.tsx @@ -26,6 +26,7 @@ import { getOpenCodeTeamModelRecommendation, isOpenCodeTeamModelRecommended, } from '@renderer/utils/openCodeModelRecommendations'; +import { isOpenCodeWindowsNodeModulesSymlinkPermissionDiagnostic } from '@shared/utils/openCodeWindowsAccessDenied'; import { AlertTriangle, Check, @@ -785,6 +786,20 @@ function getRuntimeProviderDiagnosticRows( .map(([label, value]) => [label, String(value)]); } +function isOpenCodeWindowsNodeModulesSymlinkPermissionError( + message: string, + diagnostics: RuntimeProviderManagementErrorDiagnosticsDto | null | undefined +): boolean { + const value = [ + message, + diagnostics?.stderrPreview ?? '', + diagnostics?.stdoutPreview ?? '', + diagnostics?.likelyCause ?? '', + ...(diagnostics?.hints ?? []), + ].join('\n'); + return isOpenCodeWindowsNodeModulesSymlinkPermissionDiagnostic(value); +} + async function writeRuntimeProviderDiagnosticsToClipboard(text: string): Promise { if (navigator.clipboard?.writeText) { try { @@ -826,6 +841,10 @@ const RuntimeProviderErrorAlert = ({ const [headline = message, ...detailLines] = message.trim().split(/\r?\n/); const fallbackDetails = detailLines.join('\n').trim(); const hints = diagnostics?.hints ?? []; + const showWindowsSymlinkPermissionHint = isOpenCodeWindowsNodeModulesSymlinkPermissionError( + message, + diagnostics + ); const copyText = useMemo( () => formatRuntimeProviderDiagnosticsCopyText(message, diagnostics), [diagnostics, message] @@ -859,6 +878,11 @@ const RuntimeProviderErrorAlert = ({
{headline || message} + {showWindowsSymlinkPermissionHint ? ( + + {t('runtimeProvider.diagnostics.windowsSymlinkAdminHint')} + + ) : null}