diff --git a/package.json b/package.json index a2eebf7..b3542fe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "autonomy-studio-launcher", - "version": "1.1.1", + "version": "1.1.2", "description": "Autonomy Studio v2 Frontend", "main": "./out/main/index.js", "author": { diff --git a/src/main/index.ts b/src/main/index.ts index 8ba6fbd..e41986f 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -739,11 +739,33 @@ async function loginTailscale( await waitForTailscaleConnected() return { ok: true, message: 'Tailscale 연결 완료' } } catch (error) { + if (isTailscalePermissionError(error)) { + try { + await runCommand('pkexec', ['/usr/bin/tailscale', ...tailscaleArgs], 60000, commandEnv) + await waitForTailscaleConnected() + + // Persist unprivileged access after the one privileged recovery login. + const operator = await ensureTailscaleOperator() + return { + ok: true, + message: operator.ok + ? 'Tailscale 연결 완료' + : 'Tailscale 연결 완료. 다음 연결을 위해 제어 권한을 다시 확인하세요.', + } + } catch (pkexecError) { + return { + ok: false, + message: commandErrorMessage( + pkexecError, + commandErrorMessage(error, 'Tailscale 제어 권한이 없습니다. 다시 연결해 주세요.'), + ), + } + } + } + return { ok: false, - message: isTailscalePermissionError(error) - ? commandErrorMessage(error, 'Tailscale 제어 권한이 없습니다. 다시 연결해 주세요.') - : commandErrorMessage(error, 'Tailscale 연결 실패'), + message: commandErrorMessage(error, 'Tailscale 연결 실패'), } } } diff --git a/src/main/lms-web-bridge.ts b/src/main/lms-web-bridge.ts index 2e7c997..8b68bca 100644 --- a/src/main/lms-web-bridge.ts +++ b/src/main/lms-web-bridge.ts @@ -1689,7 +1689,7 @@ done` const buildOnly = body.buildOnly === true const configuredImage = typeof body.dockerImage === 'string' ? body.dockerImage.trim() : module.dockerImage?.trim() const nav2Launch = nav2LaunchSpec(module.folderName) - const runtimeImage = configuredImage || (nav2Launch ? 'nav2-dev:humble' : AUTOWARE_IMAGE) + const runtimeImage = configuredImage || (nav2Launch ? 'future-nav2-gazebo:humble' : AUTOWARE_IMAGE) if (!/^[A-Za-z0-9._/:@-]+$/.test(runtimeImage)) throw new Error('모듈 런타임 이미지가 올바르지 않습니다.') const nav2RunCommand = nav2Launch ? `set -e; source /opt/ros/humble/setup.bash; for setup in /modules/*/install/setup.bash; do [ -f "${'$'}setup" ] && source "${'$'}setup"; done; exec ros2 launch ${nav2Launch.packageName} ${nav2Launch.launchFile} ${'$'}1` diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 11dbe5f..a7fb2a7 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -61,7 +61,6 @@ function App(): React.JSX.Element { blockLauncherSessionRefresh() window.launcherSession?.endUserSession().catch(() => undefined) requestLogout(authSession?.accessToken) - window.launcherTailscale?.logout().catch(() => undefined) window.localStorage.removeItem(AUTH_SESSION_KEY) window.sessionStorage.removeItem(AUTH_SESSION_KEY) setAuthSession(null) diff --git a/src/renderer/src/pages/Dashboard.tsx b/src/renderer/src/pages/Dashboard.tsx index 8e73707..5e2dd0c 100644 --- a/src/renderer/src/pages/Dashboard.tsx +++ b/src/renderer/src/pages/Dashboard.tsx @@ -288,17 +288,6 @@ function Dashboard({ authSession, onSessionUpdate, onLogout, onSessionExpired }: const sshKey = await window.launcherSshKey?.ensure().catch(() => null) if (cancelled) return - const operator = await launcherTailscale.ensureOperator() - if (cancelled) return - if (!operator.ok) { - setTailscaleIssue({ - state: 'warning', - title: '원격 연결 권한 필요', - message: operator.message || 'Tailscale 제어 권한을 설정하지 못했습니다.', - }) - return - } - const response = await fetchWithAuthRefreshRef.current(`${LAUNCHER_API_BASE_URL}/api/provision/session`, { method: 'POST', headers: { 'Content-Type': 'application/json' },