mirror of
https://github.com/tiennm99/ccs.git
synced 2026-07-16 00:22:34 +00:00
fix(cliproxy): respect configured local port instead of hardcoding 8317
All call sites that spawn or probe CLIProxyApiPlus now read cliproxy_server.local.port from config via resolveLifecyclePort() instead of using the hardcoded CLIPROXY_DEFAULT_PORT constant. - Move resolveLifecyclePort helper to src/cliproxy/config/port-manager.ts - Fix 7 call sites: ccs.ts, config-command.ts, copilot-executor.ts, lifecycle.ts, binary-manager.ts, cliproxy-stats-routes.ts, cliproxy-local-proxy.ts - Remove duplicate resolveLocalCliproxyPort helper - Cache port resolution in /proxy-status handler to avoid repeated I/O Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+3
-3
@@ -22,7 +22,7 @@ import {
|
||||
isAuthenticated,
|
||||
} from './cliproxy';
|
||||
import { getEffectiveEnvVars, getCompositeEnvVars } from './cliproxy/config/env-builder';
|
||||
import { CLIPROXY_DEFAULT_PORT } from './cliproxy/config/port-manager';
|
||||
import { resolveLifecyclePort } from './cliproxy/config/port-manager';
|
||||
import {
|
||||
ensureWebSearchMcpOrThrow,
|
||||
displayWebSearchStatus,
|
||||
@@ -929,7 +929,7 @@ async function main(): Promise<void> {
|
||||
}
|
||||
const customSettingsPath = profileInfo.settingsPath; // undefined for hardcoded profiles
|
||||
const variantPort = profileInfo.port; // variant-specific port for isolation
|
||||
const cliproxyPort = variantPort || CLIPROXY_DEFAULT_PORT;
|
||||
const cliproxyPort = variantPort || resolveLifecyclePort();
|
||||
|
||||
if (resolvedTarget !== 'claude') {
|
||||
const adapter = targetAdapter;
|
||||
@@ -1385,7 +1385,7 @@ async function main(): Promise<void> {
|
||||
};
|
||||
} else if (imageAnalysisStatus.proxyReadiness === 'stopped') {
|
||||
const ensureServiceResult = await ensureCliproxyService(
|
||||
CLIPROXY_DEFAULT_PORT,
|
||||
resolveLifecyclePort(),
|
||||
verboseProxyLaunch
|
||||
);
|
||||
if (!ensureServiceResult.started) {
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { info, warn } from '../utils/ui';
|
||||
import { getBinDir, CLIPROXY_DEFAULT_PORT } from './config/config-generator';
|
||||
import { getBinDir } from './config/config-generator';
|
||||
import { resolveLifecyclePort } from './config/port-manager';
|
||||
import { BinaryInfo, BinaryManagerConfig } from './types';
|
||||
import {
|
||||
BACKEND_CONFIG,
|
||||
@@ -340,7 +341,7 @@ export async function installCliproxyVersion(
|
||||
const result = await stopProxyFn();
|
||||
if (result.stopped) {
|
||||
// Wait for port to be fully released
|
||||
const portFree = await waitForPortFreeFn(CLIPROXY_DEFAULT_PORT, 5000);
|
||||
const portFree = await waitForPortFreeFn(resolveLifecyclePort(), 5000);
|
||||
if (!portFree && verbose) {
|
||||
console.log(formatWarn('Port did not free up in time, proceeding anyway...'));
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
import { downloadAndInstall, deleteBinary, getBinaryPath } from './installer';
|
||||
import { info, warn } from '../../utils/ui';
|
||||
import { isCliproxyRunning } from '../services/stats-fetcher';
|
||||
import { CLIPROXY_DEFAULT_PORT } from '../config/config-generator';
|
||||
import { resolveLifecyclePort } from '../config/port-manager';
|
||||
import {
|
||||
CLIPROXY_MAX_STABLE_VERSION,
|
||||
CLIPROXY_FAULTY_RANGE,
|
||||
@@ -82,7 +82,7 @@ async function handleAutoUpdate(config: BinaryManagerConfig, verbose: boolean):
|
||||
return;
|
||||
}
|
||||
|
||||
const proxyRunning = await isCliproxyRunning(CLIPROXY_DEFAULT_PORT);
|
||||
const proxyRunning = await isCliproxyRunning(resolveLifecyclePort());
|
||||
const latestNote = isAboveMaxStable(latestVersion) ? ` (latest v${latestVersion} unstable)` : '';
|
||||
const updateMsg = `${backendLabel} update: v${currentVersion} -> v${targetVersion}${latestNote}`;
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
* Handles port number validation and default port resolution
|
||||
*/
|
||||
|
||||
import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader';
|
||||
import type { UnifiedConfig } from '../../config/unified-config-types';
|
||||
|
||||
/** Default CLIProxy port */
|
||||
export const CLIPROXY_DEFAULT_PORT = 8317;
|
||||
|
||||
@@ -57,3 +60,13 @@ export function normalizeProtocol(protocol: string | undefined): 'http' | 'https
|
||||
// Invalid protocol (e.g., 'ftp') - default to http
|
||||
return 'http';
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the local CLIProxy lifecycle port from unified config.
|
||||
* Falls back to default port when unset/invalid.
|
||||
*/
|
||||
export function resolveLifecyclePort(
|
||||
config: Pick<UnifiedConfig, 'cliproxy_server'> = loadOrCreateUnifiedConfig()
|
||||
): number {
|
||||
return validatePort(config.cliproxy_server?.local?.port ?? CLIPROXY_DEFAULT_PORT);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
import { initUI, header, color, dim, ok, warn, info } from '../../utils/ui';
|
||||
import { getProxyStatus, startProxy, stopProxy } from '../../cliproxy/services';
|
||||
import { detectRunningProxy } from '../../cliproxy/proxy/proxy-detector';
|
||||
import { resolveLifecyclePort } from './resolve-lifecycle-port';
|
||||
import { resolveLifecyclePort } from '../../cliproxy/config/port-manager';
|
||||
|
||||
export async function handleStart(verbose = false): Promise<void> {
|
||||
await initUI();
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
import { CLIPROXY_DEFAULT_PORT, validatePort } from '../../cliproxy/config/port-manager';
|
||||
import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader';
|
||||
import type { UnifiedConfig } from '../../config/unified-config-types';
|
||||
|
||||
type LifecyclePortConfig = Pick<UnifiedConfig, 'cliproxy_server'>;
|
||||
|
||||
/**
|
||||
* Resolve the local CLIProxy lifecycle port from unified config.
|
||||
* Falls back to default port when unset/invalid.
|
||||
*/
|
||||
export function resolveLifecyclePort(
|
||||
config: LifecyclePortConfig = loadOrCreateUnifiedConfig()
|
||||
): number {
|
||||
return validatePort(config.cliproxy_server?.local?.port ?? CLIPROXY_DEFAULT_PORT);
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import open from 'open';
|
||||
import { startServer } from '../web-server';
|
||||
import { setupGracefulShutdown } from '../web-server/shutdown';
|
||||
import { ensureCliproxyService } from '../cliproxy/service-manager';
|
||||
import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/config-generator';
|
||||
import { resolveLifecyclePort } from '../cliproxy/config/port-manager';
|
||||
import { getDashboardAuthConfig } from '../config/unified-config-loader';
|
||||
import { initUI, header, ok, info, warn, fail } from '../utils/ui';
|
||||
import { resolveNamedCommand, type NamedCommandRoute } from './named-command-router';
|
||||
@@ -137,7 +137,7 @@ export async function handleConfigCommand(
|
||||
|
||||
// Ensure CLIProxy service is running for dashboard features
|
||||
console.log(deps.info('Starting CLIProxy service...'));
|
||||
const cliproxyResult = await deps.ensureCliproxyService(CLIPROXY_DEFAULT_PORT, verbose);
|
||||
const cliproxyResult = await deps.ensureCliproxyService(resolveLifecyclePort(), verbose);
|
||||
logger.info('cliproxy.ensure_result', 'Config command checked CLIProxy availability', {
|
||||
started: cliproxyResult.started,
|
||||
alreadyRunning: cliproxyResult.alreadyRunning,
|
||||
|
||||
@@ -10,7 +10,7 @@ import { CopilotConfig } from '../config/unified-config-types';
|
||||
import { getGlobalEnvConfig } from '../config/unified-config-loader';
|
||||
import { ensureCliproxyService } from '../cliproxy';
|
||||
import { getEffectiveApiKey } from '../cliproxy/auth/auth-token-manager';
|
||||
import { CLIPROXY_DEFAULT_PORT } from '../cliproxy/config/port-manager';
|
||||
import { resolveLifecyclePort } from '../cliproxy/config/port-manager';
|
||||
import { checkAuthStatus, isCopilotApiInstalled } from './copilot-auth';
|
||||
import { isDaemonRunning, startDaemon } from './copilot-daemon';
|
||||
import { ensureCopilotApi } from './copilot-package-manager';
|
||||
@@ -142,7 +142,7 @@ export async function resolveCopilotImageAnalysisEnv(
|
||||
|
||||
if (status.proxyReadiness === 'stopped') {
|
||||
const ensureServiceResult = await resolvedDeps.ensureCliproxyService(
|
||||
CLIPROXY_DEFAULT_PORT,
|
||||
resolveLifecyclePort(),
|
||||
verbose
|
||||
);
|
||||
if (!ensureServiceResult.started) {
|
||||
|
||||
@@ -9,8 +9,7 @@
|
||||
|
||||
import http from 'http';
|
||||
import { Request, Response, Router } from 'express';
|
||||
import { CLIPROXY_DEFAULT_PORT, validatePort } from '../../cliproxy/config/port-manager';
|
||||
import { loadOrCreateUnifiedConfig } from '../../config/unified-config-loader';
|
||||
import { resolveLifecyclePort } from '../../cliproxy/config/port-manager';
|
||||
import { requireLocalAccessWhenAuthDisabled } from '../middleware/auth-middleware';
|
||||
|
||||
export interface CliproxyLocalProxyDeps {
|
||||
@@ -22,15 +21,6 @@ export interface CliproxyLocalProxyDeps {
|
||||
/** Proxy request timeout in milliseconds (30 seconds) */
|
||||
const PROXY_TIMEOUT_MS = 30_000;
|
||||
|
||||
function resolveLocalCliproxyPort(): number {
|
||||
try {
|
||||
const config = loadOrCreateUnifiedConfig();
|
||||
return validatePort(config.cliproxy_server?.local?.port ?? CLIPROXY_DEFAULT_PORT);
|
||||
} catch {
|
||||
return CLIPROXY_DEFAULT_PORT;
|
||||
}
|
||||
}
|
||||
|
||||
function isJsonContentType(contentType: string | string[] | undefined): boolean {
|
||||
const values = Array.isArray(contentType) ? contentType : [contentType];
|
||||
return values.some((value) => value?.toLowerCase().includes('application/json') === true);
|
||||
@@ -82,7 +72,7 @@ export function createCliproxyLocalProxyRouter(deps: CliproxyLocalProxyDeps = {}
|
||||
'CLIProxy local proxy requires localhost access when dashboard auth is disabled.'
|
||||
));
|
||||
const createRequest = deps.request ?? http.request;
|
||||
const resolveTargetPort = deps.resolveTargetPort ?? resolveLocalCliproxyPort;
|
||||
const resolveTargetPort = deps.resolveTargetPort ?? resolveLifecyclePort;
|
||||
|
||||
router.use((req: Request, res: Response, next) => {
|
||||
if (enforceAccess(req, res)) {
|
||||
|
||||
@@ -52,7 +52,7 @@ import {
|
||||
CLIPROXY_MAX_STABLE_VERSION,
|
||||
CLIPROXY_FAULTY_RANGE,
|
||||
} from '../../cliproxy/binary/platform-detector';
|
||||
import { CLIPROXY_DEFAULT_PORT } from '../../cliproxy/config/port-manager';
|
||||
import { resolveLifecyclePort } from '../../cliproxy/config/port-manager';
|
||||
import {
|
||||
MODEL_ENV_VAR_KEYS,
|
||||
canonicalizeModelIdForProvider,
|
||||
@@ -321,7 +321,7 @@ router.get('/usage', handleStatsRequest);
|
||||
*/
|
||||
router.get('/status', async (_req: Request, res: Response): Promise<void> => {
|
||||
try {
|
||||
const running = await isCliproxyRunning();
|
||||
const running = await isCliproxyRunning(resolveLifecyclePort());
|
||||
res.json({ running });
|
||||
} catch (error) {
|
||||
console.error(`[cliproxy-stats] ${(error as Error).message}`);
|
||||
@@ -345,15 +345,16 @@ router.get('/proxy-status', async (_req: Request, res: Response): Promise<void>
|
||||
return;
|
||||
}
|
||||
|
||||
const port = resolveLifecyclePort();
|
||||
// Session tracker says not running, but proxy might be running without session tracking
|
||||
// (e.g., started before session persistence was implemented)
|
||||
const actuallyRunning = await isCliproxyRunning();
|
||||
const actuallyRunning = await isCliproxyRunning(port);
|
||||
|
||||
if (actuallyRunning) {
|
||||
// Proxy running but no session lock - legacy/untracked instance
|
||||
res.json({
|
||||
running: true,
|
||||
port: CLIPROXY_DEFAULT_PORT,
|
||||
port,
|
||||
sessionCount: 0, // Unknown sessions
|
||||
// No pid/startedAt since we don't have session lock
|
||||
});
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { describe, expect, it } from 'bun:test';
|
||||
import { CLIPROXY_DEFAULT_PORT } from '../../../src/cliproxy/config/port-manager';
|
||||
import { resolveLifecyclePort } from '../../../src/commands/cliproxy/resolve-lifecycle-port';
|
||||
import { CLIPROXY_DEFAULT_PORT, resolveLifecyclePort } from '../../../src/cliproxy/config/port-manager';
|
||||
|
||||
describe('resolveLifecyclePort', () => {
|
||||
it('uses configured cliproxy_server.local.port', () => {
|
||||
|
||||
Reference in New Issue
Block a user