diff --git a/apps/kimi-code/src/cli/sub/web/remote-control.ts b/apps/kimi-code/src/cli/sub/web/remote-control.ts index 8fe5f8a983f..42cd221f980 100644 --- a/apps/kimi-code/src/cli/sub/web/remote-control.ts +++ b/apps/kimi-code/src/cli/sub/web/remote-control.ts @@ -19,6 +19,8 @@ import { acquireRemoteControlLock } from './remote-control-lock'; export const REMOTE_CONTROL_RELAY_ORIGIN = 'https://code-rc.kimi.com'; +export const REMOTE_CONTROL_RELAY_URL_ENV = 'KIMI_CODE_REMOTE_CONTROL_RELAY_URL'; + export const REMOTE_CONTROL_FLAG_ENV = 'KIMI_CODE_EXPERIMENTAL_REMOTE_CONTROL'; const TRUTHY_ENV_VALUES = new Set(['1', 'true', 'yes', 'on']); @@ -31,6 +33,13 @@ export function isRemoteControlEnabled( return truthy('KIMI_CODE_EXPERIMENTAL_FLAG') || truthy(REMOTE_CONTROL_FLAG_ENV); } +export function resolveRemoteControlRelayOrigin( + env: Readonly> = process.env, +): string { + const value = env[REMOTE_CONTROL_RELAY_URL_ENV]?.trim(); + return value === undefined || value.length === 0 ? REMOTE_CONTROL_RELAY_ORIGIN : value; +} + const MAX_HTTP_HEADER_BYTES = 64 * 1024; const MAX_HTTP_REQUEST_BYTES = 10 * 1024 * 1024; const HTTP_REQUEST_TIMEOUT_MS = 30_000; @@ -174,7 +183,7 @@ export function formatRemoteControlStatus(status: RemoteControlStatus): string { export function buildRemoteControlUrl( deviceId: string, sessionId?: string, - relayOrigin = REMOTE_CONTROL_RELAY_ORIGIN, + relayOrigin = resolveRemoteControlRelayOrigin(), ): string { const url = new URL(relayOrigin); const relayPath = url.pathname.replace(/\/+$/, ''); @@ -291,7 +300,7 @@ export async function startRemoteControl( if (token?.refreshToken === undefined || token.refreshToken.length === 0) { throw new Error('Remote Control requires a Kimi login. Run `kimi login` first.'); } - const relayOrigin = options.relayOrigin ?? REMOTE_CONTROL_RELAY_ORIGIN; + const relayOrigin = options.relayOrigin ?? resolveRemoteControlRelayOrigin(); const deviceId = createKimiDeviceId(options.homeDir); const deviceName = hostname(); const url = buildRemoteControlUrl(deviceId, undefined, relayOrigin); diff --git a/apps/kimi-code/test/cli/web/remote-control.test.ts b/apps/kimi-code/test/cli/web/remote-control.test.ts index 8329f919eca..56cf347a377 100644 --- a/apps/kimi-code/test/cli/web/remote-control.test.ts +++ b/apps/kimi-code/test/cli/web/remote-control.test.ts @@ -21,6 +21,7 @@ import { formatRemoteControlStatus, isRemoteControlEnabled, parseRawHttpRequest, + resolveRemoteControlRelayOrigin, rewriteRemoteControlResponse, startRemoteControl, type RemoteControlHandle, @@ -72,6 +73,21 @@ describe('Remote Control URLs', () => { 'https://code-rc.kimi.com/devices/device-1/sessions/session%2Fa%20b?rc=1&from=kimi_code_cli', ); }); + + it('falls back to the default relay origin when the env is unset or blank', () => { + expect(resolveRemoteControlRelayOrigin({})).toBe('https://code-rc.kimi.com'); + expect( + resolveRemoteControlRelayOrigin({ KIMI_CODE_REMOTE_CONTROL_RELAY_URL: ' ' }), + ).toBe('https://code-rc.kimi.com'); + }); + + it('builds device URLs from the relay origin env override', () => { + vi.stubEnv('KIMI_CODE_REMOTE_CONTROL_RELAY_URL', 'https://rc.example.test/coding-relay/'); + expect(resolveRemoteControlRelayOrigin()).toBe('https://rc.example.test/coding-relay/'); + expect(buildRemoteControlUrl('device-1')).toBe( + 'https://rc.example.test/coding-relay/devices/device-1/?rc=1&from=kimi_code_cli', + ); + }); }); describe('Remote Control output', () => {