From 2fe8f2b4ca68865a7cc9c9dd9f6c2d59fe27a53a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 14 Feb 2026 02:33:13 +0000 Subject: [PATCH 1/3] chore(release): 7.43.0-dev.16 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a73a123..96e5a83a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kaitranntt/ccs", - "version": "7.43.0-dev.15", + "version": "7.43.0-dev.16", "description": "Claude Code Switch - Instant profile switching between Claude Sonnet 4.5 and GLM 4.6", "keywords": [ "cli", From 83953649704c5957a2522e3b8cf041fd2725510e Mon Sep 17 00:00:00 2001 From: Tam Nhu Tran Date: Sat, 14 Feb 2026 09:41:14 +0700 Subject: [PATCH 2/3] feat(cliproxy): add explicit start and restart commands --- README.md | 9 +++ src/cliproxy/services/index.ts | 2 + .../services/proxy-lifecycle-service.ts | 23 +++++++- src/commands/cliproxy/help-subcommand.ts | 2 + src/commands/cliproxy/index.ts | 17 +++++- .../cliproxy/proxy-lifecycle-subcommand.ts | 55 ++++++++++++++++++- tests/unit/commands/cliproxy-command.test.js | 14 ++++- 7 files changed, 118 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b3125fb0..b4861825 100644 --- a/README.md +++ b/README.md @@ -229,6 +229,15 @@ ccs cliproxy doctor # Check quota status for all agy accounts **Auto-Failover**: When an Antigravity account runs out of quota, CCS automatically switches to another account with remaining capacity. Shared GCP project accounts are excluded (pooled quota). +### CLIProxy Lifecycle + +```bash +ccs cliproxy start # Start CLIProxy background service +ccs cliproxy status # Check running status +ccs cliproxy restart # Restart CLIProxy service +ccs cliproxy stop # Stop running CLIProxy service +``` +
## Configuration diff --git a/src/cliproxy/services/index.ts b/src/cliproxy/services/index.ts index b8fa43de..b67ed7a3 100644 --- a/src/cliproxy/services/index.ts +++ b/src/cliproxy/services/index.ts @@ -22,10 +22,12 @@ export { export { getProxyStatus, stopProxy, + startProxy, isProxyRunning, getActiveSessionCount, type ProxyStatusResult, type StopProxyResult, + type StartProxyResult, } from './proxy-lifecycle-service'; // Binary management diff --git a/src/cliproxy/services/proxy-lifecycle-service.ts b/src/cliproxy/services/proxy-lifecycle-service.ts index 7ea4c124..ecd888d9 100644 --- a/src/cliproxy/services/proxy-lifecycle-service.ts +++ b/src/cliproxy/services/proxy-lifecycle-service.ts @@ -2,13 +2,15 @@ * CLIProxy Proxy Lifecycle Service * * Handles start/stop/status operations for CLIProxy instances. - * Delegates to session-tracker for actual process management. + * Delegates to session-tracker and service-manager for actual process management. */ import { stopProxy as stopProxySession, getProxyStatus as getProxyStatusSession, } from '../session-tracker'; +import { ensureCliproxyService } from '../service-manager'; +import { CLIPROXY_DEFAULT_PORT } from '../config-generator'; /** Proxy status result */ export interface ProxyStatusResult { @@ -27,6 +29,15 @@ export interface StopProxyResult { error?: string; } +/** Start proxy result */ +export interface StartProxyResult { + started: boolean; + alreadyRunning: boolean; + port: number; + configRegenerated?: boolean; + error?: string; +} + /** * Get current proxy status */ @@ -41,6 +52,16 @@ export async function stopProxy(): Promise { return stopProxySession(); } +/** + * Start CLIProxy service (or reuse existing running instance) + */ +export async function startProxy( + port: number = CLIPROXY_DEFAULT_PORT, + verbose: boolean = false +): Promise { + return ensureCliproxyService(port, verbose); +} + /** * Check if proxy is currently running */ diff --git a/src/commands/cliproxy/help-subcommand.ts b/src/commands/cliproxy/help-subcommand.ts index fe136927..7971c701 100644 --- a/src/commands/cliproxy/help-subcommand.ts +++ b/src/commands/cliproxy/help-subcommand.ts @@ -61,6 +61,8 @@ export async function showHelp(): Promise { [ 'Proxy Lifecycle:', [ + ['start', 'Start CLIProxy instance in background'], + ['restart', 'Restart CLIProxy instance'], ['status', 'Show running CLIProxy status'], ['stop', 'Stop running CLIProxy instance'], ['doctor', 'Quota diagnostics and shared project detection'], diff --git a/src/commands/cliproxy/index.ts b/src/commands/cliproxy/index.ts index bdefb355..308f9838 100644 --- a/src/commands/cliproxy/index.ts +++ b/src/commands/cliproxy/index.ts @@ -20,7 +20,12 @@ import { handleResumeAccount, } from './quota-subcommand'; import { handleCreate, handleRemove, handleEdit } from './variant-subcommand'; -import { handleProxyStatus, handleStop } from './proxy-lifecycle-subcommand'; +import { + handleProxyStatus, + handleStart, + handleStop, + handleRestart, +} from './proxy-lifecycle-subcommand'; import { showStatus, handleInstallVersion, handleInstallLatest } from './install-subcommand'; import { showHelp } from './help-subcommand'; import { @@ -198,11 +203,21 @@ export async function handleCliproxyCommand(args: string[]): Promise { } // Proxy lifecycle commands + if (command === 'start') { + await handleStart(verbose); + return; + } + if (command === 'stop') { await handleStop(); return; } + if (command === 'restart') { + await handleRestart(verbose); + return; + } + if (command === 'status') { await handleProxyStatus(); return; diff --git a/src/commands/cliproxy/proxy-lifecycle-subcommand.ts b/src/commands/cliproxy/proxy-lifecycle-subcommand.ts index d59319c2..c2983ecb 100644 --- a/src/commands/cliproxy/proxy-lifecycle-subcommand.ts +++ b/src/commands/cliproxy/proxy-lifecycle-subcommand.ts @@ -2,15 +2,68 @@ * CLIProxy Lifecycle Management * * Handles: + * - ccs cliproxy start + * - ccs cliproxy restart * - ccs cliproxy status * - ccs cliproxy stop */ import { initUI, header, color, dim, ok, warn, info } from '../../utils/ui'; -import { getProxyStatus, stopProxy } from '../../cliproxy/services'; +import { getProxyStatus, startProxy, stopProxy } from '../../cliproxy/services'; import { detectRunningProxy } from '../../cliproxy/proxy-detector'; import { CLIPROXY_DEFAULT_PORT } from '../../cliproxy/config-generator'; +export async function handleStart(verbose = false): Promise { + await initUI(); + console.log(header('Start CLIProxy')); + console.log(''); + + const result = await startProxy(CLIPROXY_DEFAULT_PORT, verbose); + if (result.started) { + if (result.alreadyRunning) { + console.log(info(`CLIProxy already running on port ${result.port}`)); + if (result.configRegenerated) { + console.log(warn('Config updated - restart CLIProxy to apply changes')); + } + } else { + console.log(ok(`CLIProxy started on port ${result.port}`)); + } + console.log(dim('To stop: ccs cliproxy stop')); + } else { + console.log(warn(result.error || 'Failed to start CLIProxy')); + } + console.log(''); +} + +export async function handleRestart(verbose = false): Promise { + await initUI(); + console.log(header('Restart CLIProxy')); + console.log(''); + + const stopResult = await stopProxy(); + if (stopResult.stopped) { + console.log(ok(`CLIProxy stopped (PID ${stopResult.pid})`)); + } else if (stopResult.error === 'No active CLIProxy session found') { + console.log(info('No active CLIProxy session found, starting a new instance')); + } else { + console.log(warn(stopResult.error || 'Failed to stop existing CLIProxy')); + console.log(info('Attempting to start a fresh instance...')); + } + + const startResult = await startProxy(CLIPROXY_DEFAULT_PORT, verbose); + if (startResult.started) { + if (startResult.alreadyRunning) { + console.log(info(`CLIProxy already running on port ${startResult.port}`)); + } else { + console.log(ok(`CLIProxy started on port ${startResult.port}`)); + } + } else { + console.log(warn(startResult.error || 'Failed to restart CLIProxy')); + } + + console.log(''); +} + export async function handleProxyStatus(): Promise { await initUI(); console.log(header('CLIProxy Status')); diff --git a/tests/unit/commands/cliproxy-command.test.js b/tests/unit/commands/cliproxy-command.test.js index 2f7c2a97..e6fc3a0b 100644 --- a/tests/unit/commands/cliproxy-command.test.js +++ b/tests/unit/commands/cliproxy-command.test.js @@ -491,6 +491,18 @@ describe('CLIProxy Command - Proxy Lifecycle', () => { }); describe('Command Routing', () => { + it('routes "start" subcommand correctly', () => { + const args = ['cliproxy', 'start']; + const subcommand = args[1]; + assert.strictEqual(subcommand, 'start'); + }); + + it('routes "restart" subcommand correctly', () => { + const args = ['cliproxy', 'restart']; + const subcommand = args[1]; + assert.strictEqual(subcommand, 'restart'); + }); + it('routes "stop" subcommand correctly', () => { const args = ['cliproxy', 'stop']; const subcommand = args[1]; @@ -504,7 +516,7 @@ describe('CLIProxy Command - Proxy Lifecycle', () => { }); it('handles unknown subcommand', () => { - const validSubcommands = ['stop', 'status', 'create', 'list', 'remove']; + const validSubcommands = ['start', 'restart', 'stop', 'status', 'create', 'list', 'remove']; const unknownCommand = 'invalid'; assert.strictEqual(validSubcommands.includes(unknownCommand), false); }); From 84e0bce99ed7b05b52f0401daf8d41839864137c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sat, 14 Feb 2026 02:43:01 +0000 Subject: [PATCH 3/3] chore(release): 7.43.0-dev.17 [skip ci] --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 96e5a83a..74a1dbaa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@kaitranntt/ccs", - "version": "7.43.0-dev.16", + "version": "7.43.0-dev.17", "description": "Claude Code Switch - Instant profile switching between Claude Sonnet 4.5 and GLM 4.6", "keywords": [ "cli",