You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maka.apache.org by wy...@apache.org on 2026/09/04 05:04:35 UTC
(maka) branch fix/windows-local-remote-access updated: fix(desktop): launch Windows local setup safely
This is an automated email from the ASF dual-hosted git repository.
M4n5ter pushed a commit to branch fix/windows-local-remote-access
in repository https://gitbox.apache.org/repos/asf/maka.git
The following commit(s) were added to refs/heads/fix/windows-local-remote-access by this push:
new 6c3cc86be2 fix(desktop): launch Windows local setup safely
6c3cc86be2 is described below
commit 6c3cc86be2012a47a4f8565bfdb7d0e750b808fd
Author: M4n5ter <m4...@gmail.com>
AuthorDate: Fri Sep 4 13:04:26 2026 +0800
fix(desktop): launch Windows local setup safely
---
.../src/main/runtime-host-local-operator.ts | 123 ++++++++++++++-------
.../src/renderer/locales/settings-projects-copy.ts | 3 +
.../settings/runtime-host-profiles-section.tsx | 12 +-
3 files changed, 98 insertions(+), 40 deletions(-)
diff --git a/apps/desktop/src/main/runtime-host-local-operator.ts b/apps/desktop/src/main/runtime-host-local-operator.ts
index 3bda1aef6b..dd6175d9c8 100644
--- a/apps/desktop/src/main/runtime-host-local-operator.ts
+++ b/apps/desktop/src/main/runtime-host-local-operator.ts
@@ -20,7 +20,7 @@
import { spawn, type ChildProcess } from 'node:child_process';
import { mkdtemp, rm, rmdir, stat } from 'node:fs/promises';
import { tmpdir } from 'node:os';
-import { dirname, join } from 'node:path';
+import { delimiter, dirname, isAbsolute, join } from 'node:path';
import { redactSecrets } from '@maka/core/redaction';
import {
DEFAULT_PROCESS_TERMINATION_GRACE_MS,
@@ -238,10 +238,14 @@ export function createDesktopRuntimeHostLocalOperator(input: {
if (closed) throw new Error('Local Runtime Host operator is closed');
setup.signal?.throwIfAborted();
const setupPackage = await resolveLocalSetupPackage(setup.setupPackage);
- const command = runtimeHostLocalSetupCommand({
- ...setup,
- packageSpecifier: setupPackage.specifier,
- });
+ const environment = input.environment ?? process.env;
+ const command = await resolveLocalNpmCommand(
+ runtimeHostLocalSetupCommand({
+ ...setup,
+ packageSpecifier: setupPackage.specifier,
+ }),
+ environment,
+ );
const workingDirectory = await mkdtemp(join(tmpdir(), 'maka-runtime-host-local-setup-'));
try {
if (closed) throw new Error('Local Runtime Host operator is closed');
@@ -251,7 +255,7 @@ export function createDesktopRuntimeHostLocalOperator(input: {
command,
cwd: workingDirectory,
environment: {
- ...(input.environment ?? process.env),
+ ...environment,
...(setupPackage.integrity
? {
[RUNTIME_HOST_SETUP_SOURCE_PACKAGE_INTEGRITY_ENV]:
@@ -387,45 +391,49 @@ export function createDesktopRuntimeHostLocalOperator(input: {
active,
}).then((frame) => requireServiceFrame(frame, command.action));
},
- runUpdate(command, onProgress) {
+ async runUpdate(command, onProgress) {
if (closed) throw new Error('Local Runtime Host operator is closed');
if (!command.target.deploymentId) {
return Promise.reject(new Error('Runtime Host update requires a deployment generation'));
}
const setupPackage = resolveLocalSetupPackage(command.setupPackage);
const targetVersion = runtimeHostSetupPackageVersion(command.setupPackage);
+ const environment = {
+ ...(input.environment ?? process.env),
+ ...(setupPackage.integrity
+ ? { [RUNTIME_HOST_SETUP_SOURCE_PACKAGE_INTEGRITY_ENV]: setupPackage.integrity }
+ : {}),
+ [RUNTIME_HOST_OPERATOR_PROJECT_DIRECTORY_CONFIGURATION_REQUEST_ENV]: '1',
+ };
return runServiceFrameProcess({
- command: {
- executable: 'npm',
- args: [
- 'exec',
- '--yes',
- '--package',
- setupPackage.specifier,
- '--',
- 'maka',
- 'runtime-host',
- 'service',
- 'update',
- '--framed',
- ...(targetVersion ? ['--target', targetVersion] : []),
- '--managed-root-id',
- command.target.rootId,
- ...(command.expectedHost
- ? ['--expected-host-json', JSON.stringify(command.expectedHost)]
- : []),
- ...managedTargetArgs(command.target),
- ...(command.allowManualUpdate && targetVersion ? ['--allow-manual-update'] : []),
- ...(command.allowInterruptActiveTasks ? ['--allow-interrupt-active-tasks'] : []),
- ],
- },
- environment: {
- ...(input.environment ?? process.env),
- ...(setupPackage.integrity
- ? { [RUNTIME_HOST_SETUP_SOURCE_PACKAGE_INTEGRITY_ENV]: setupPackage.integrity }
- : {}),
- [RUNTIME_HOST_OPERATOR_PROJECT_DIRECTORY_CONFIGURATION_REQUEST_ENV]: '1',
- },
+ command: await resolveLocalNpmCommand(
+ {
+ executable: 'npm',
+ args: [
+ 'exec',
+ '--yes',
+ '--package',
+ setupPackage.specifier,
+ '--',
+ 'maka',
+ 'runtime-host',
+ 'service',
+ 'update',
+ '--framed',
+ ...(targetVersion ? ['--target', targetVersion] : []),
+ '--managed-root-id',
+ command.target.rootId,
+ ...(command.expectedHost
+ ? ['--expected-host-json', JSON.stringify(command.expectedHost)]
+ : []),
+ ...managedTargetArgs(command.target),
+ ...(command.allowManualUpdate && targetVersion ? ['--allow-manual-update'] : []),
+ ...(command.allowInterruptActiveTasks ? ['--allow-interrupt-active-tasks'] : []),
+ ],
+ },
+ environment,
+ ),
+ environment,
spawnProcess: input.spawnProcess ?? spawn,
timeoutMs: input.setupTimeoutMs ?? SETUP_TIMEOUT_MS,
terminate,
@@ -662,6 +670,45 @@ function resolveLocalSetupPackage(
return { specifier: setupPackage.path, integrity: setupPackage.integrity };
}
+async function resolveLocalNpmCommand(
+ command: DesktopRuntimeHostLocalSetupCommand,
+ environment: NodeJS.ProcessEnv,
+): Promise<DesktopRuntimeHostLocalSetupCommand> {
+ if (process.platform !== 'win32' || command.executable !== 'npm') return command;
+
+ const configuredNode = environment.npm_node_execpath;
+ const configuredCli = environment.npm_execpath;
+ const candidates: Array<readonly [string, string]> = [];
+ if (configuredNode && configuredCli) candidates.push([configuredNode, configuredCli]);
+
+ const path = Object.entries(environment).find(([key]) => key.toUpperCase() === 'PATH')?.[1];
+ for (const entry of path?.split(delimiter) ?? []) {
+ const directory = entry.replace(/^"|"$/gu, '').trim();
+ if (!directory) continue;
+ candidates.push([
+ join(directory, 'node.exe'),
+ join(directory, 'node_modules', 'npm', 'bin', 'npm-cli.js'),
+ ]);
+ }
+
+ for (const [nodePath, cliPath] of candidates) {
+ if (!isAbsolute(nodePath) || !isAbsolute(cliPath)) continue;
+ if ((await regularFile(nodePath)) && (await regularFile(cliPath))) {
+ return { executable: nodePath, args: [cliPath, ...command.args] };
+ }
+ }
+ throw new Error('Local Runtime Host setup requires a complete Node.js and npm installation');
+}
+
+async function regularFile(path: string): Promise<boolean> {
+ try {
+ return (await stat(path)).isFile();
+ } catch (error) {
+ if (isNodeError(error, 'ENOENT')) return false;
+ throw error;
+ }
+}
+
function managedTargetArgs(target: DesktopRuntimeHostLocalServiceTarget): string[] {
return [
'--expected-service-id',
diff --git a/apps/desktop/src/renderer/locales/settings-projects-copy.ts b/apps/desktop/src/renderer/locales/settings-projects-copy.ts
index 3666a18ddd..fa2aee3c2c 100644
--- a/apps/desktop/src/renderer/locales/settings-projects-copy.ts
+++ b/apps/desktop/src/renderer/locales/settings-projects-copy.ts
@@ -38,6 +38,7 @@ export type SettingsProjectsCopy = {
configureManuallyDescription: string;
thisComputerRemoteAccess: string;
thisComputerRemoteAccessHelp: string;
+ remoteAccessEnabling: string;
remoteAccessOn: string;
remoteAccessOff: string;
enableRemoteAccess: string;
@@ -329,6 +330,7 @@ const SETTINGS_PROJECTS_COPY_BY_LOCALE = {
configureManuallyDescription: '为已有 Host 填写 TLS、SSH 或 Direct peer 参数',
thisComputerRemoteAccess: '远程访问',
thisComputerRemoteAccessHelp: '通过实验性端到端直连访问此 Host;可自动发现公共协调节点来辅助打洞',
+ remoteAccessEnabling: '正在准备并开启远程访问;首次可能需要一点时间。',
remoteAccessOn: '已开启',
remoteAccessOff: '未开启',
enableRemoteAccess: '开启',
@@ -645,6 +647,7 @@ const SETTINGS_PROJECTS_COPY_BY_LOCALE = {
configureManuallyDescription: 'Enter TLS, SSH, or Direct peer details for an existing Host',
thisComputerRemoteAccess: 'Remote access',
thisComputerRemoteAccessHelp: 'Reach this Host through experimental end-to-end direct connections, with automatic public coordination discovery',
+ remoteAccessEnabling: 'Preparing and enabling remote access. The first setup may take a moment.',
remoteAccessOn: 'On',
remoteAccessOff: 'Off',
enableRemoteAccess: 'Enable',
diff --git a/apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx b/apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx
index 3e39df880f..6d60724cda 100644
--- a/apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx
+++ b/apps/desktop/src/renderer/settings/runtime-host-profiles-section.tsx
@@ -112,6 +112,7 @@ export function RuntimeHostProfilesSection(props: {
const [showJoinSharedSession, setShowJoinSharedSession] = useState(false);
const [managedTarget, setManagedTarget] = useState<RuntimeHostManagementTarget>();
const [localAccess, setLocalAccess] = useState<DesktopLocalRuntimeHostRemoteAccessSnapshot>();
+ const [localAccessEnabling, setLocalAccessEnabling] = useState(false);
const [connectionCodeDialog, setConnectionCodeDialog] = useState<
| { readonly mode: 'import' }
| {
@@ -263,6 +264,7 @@ export function RuntimeHostProfilesSection(props: {
async function enableLocalRemoteAccess(allowInterruptActiveTasks = false): Promise<void> {
setSwitching(true);
+ setLocalAccessEnabling(true);
try {
const result = await window.maka.localRuntimeHostRemoteAccess.enable({
allowInterruptActiveTasks,
@@ -298,7 +300,10 @@ export function RuntimeHostProfilesSection(props: {
);
}
} finally {
- if (mountedRef.current) setSwitching(false);
+ if (mountedRef.current) {
+ setSwitching(false);
+ setLocalAccessEnabling(false);
+ }
}
}
@@ -399,7 +404,9 @@ export function RuntimeHostProfilesSection(props: {
<SettingsRow
label={copy.thisComputerRemoteAccess}
description={
- localAccess?.state === 'unsupported'
+ localAccessEnabling
+ ? copy.remoteAccessEnabling
+ : localAccess?.state === 'unsupported'
? localAccess.message
: localAccess?.state === 'unavailable'
? localAccess.message
@@ -450,6 +457,7 @@ export function RuntimeHostProfilesSection(props: {
variant="secondary"
size="sm"
label={copy.enableRemoteAccess}
+ isLoading={localAccessEnabling}
isDisabled={
switching ||
!localAccess ||
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@maka.apache.org
For additional commands, e-mail: commits-help@maka.apache.org