fix(cli): accept --daemon on start and serve commands

Fixes #1246. Parse --daemon for service commands and route serve/web
through startService when it is set so foreground serve can run in the
background. start and ui already daemonize by default; the flag is now
accepted for backward compatibility with documented usage.

Tests: npm --workspace @musistudio/claude-code-router test (6 passed)
This commit is contained in:
syf2211 2026-09-10 00:09:52 +00:00
parent 5ad5083b4e
commit 2f905c327e
No known key found for this signature in database
2 changed files with 39 additions and 9 deletions

View file

@ -29,6 +29,7 @@ type ProfileCliOptions = {
type WebCliOptions = {
command: "start" | "ui" | "web";
daemon: boolean;
daemonChild: boolean;
ensureGatewayRunning: boolean;
help: boolean;
@ -101,6 +102,13 @@ async function main(): Promise<void> {
printWebHelp(0);
return;
}
if (options.daemon) {
await startService({
...options,
command: "start"
});
return;
}
await runWebServer(options);
return;
}
@ -130,6 +138,7 @@ async function main(): Promise<void> {
if (profile.agent === "codex" && resolvedSurface === "app" && profileOptions.agentArgs.length === 0) {
const state = await startService({
command: "start",
daemon: false,
daemonChild: false,
ensureGatewayRunning: true,
help: false,
@ -158,6 +167,7 @@ async function main(): Promise<void> {
profileGatewayLease ??= createProfileGatewayLease();
await startService({
command: "start",
daemon: false,
daemonChild: false,
ensureGatewayRunning: true,
help: false,
@ -313,6 +323,7 @@ function parseStopArgs(args: string[]): StopCliOptions {
function parseWebArgs(args: string[], command: WebCliOptions["command"], defaultOpen = false): WebCliOptions {
const options: WebCliOptions = {
command,
daemon: false,
daemonChild: false,
ensureGatewayRunning: false,
help: false,
@ -342,8 +353,12 @@ function parseWebArgs(args: string[], command: WebCliOptions["command"], default
options.startGateway = false;
continue;
}
if (arg === "--daemon-child") {
options.daemonChild = true;
if (arg === "--daemon" || arg === "--daemon-child") {
if (arg === "--daemon") {
options.daemon = true;
} else {
options.daemonChild = true;
}
continue;
}
if (arg === "--profile-managed") {
@ -569,9 +584,9 @@ function printHelp(exitCode: number): void {
const command = cliCommandName();
const output = [
"Usage:",
` ${command} start [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} ui [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} serve [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} start [--daemon] [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} ui [--daemon] [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} serve [--daemon] [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} stop`,
` ${command} <profile-name-or-id> [cli|app] [-- <agent args>]`,
"",
@ -598,9 +613,10 @@ function printStartHelp(exitCode: number): void {
const command = cliCommandName();
const output = [
"Usage:",
` ${command} start [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} start [--daemon] [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
"",
"Options:",
" --daemon Run the management server in the background (default for start).",
" --host <host> Management server host. Defaults to CCR_WEB_HOST or 127.0.0.1.",
" --port <port> Management server port. Defaults to CCR_WEB_PORT or 3458.",
" --open Open the management page in the default browser.",
@ -622,11 +638,12 @@ function printUiHelp(exitCode: number): void {
const command = cliCommandName();
const output = [
"Usage:",
` ${command} ui [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} ui [--daemon] [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
"",
"Starts the background CCR service if needed and opens the management UI in the default browser.",
"",
"Options:",
" --daemon Run the management server in the background (default for ui).",
" --host <host> Management server host. Defaults to CCR_WEB_HOST or 127.0.0.1.",
" --port <port> Management server port. Defaults to CCR_WEB_PORT or 3458.",
" --open Open the management page (default).",
@ -661,11 +678,12 @@ function printWebHelp(exitCode: number): void {
const command = cliCommandName();
const output = [
"Usage:",
` ${command} serve [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
` ${command} serve [--daemon] [--host <host>] [--port <port>] [--open|--no-open] [--gateway|--no-gateway]`,
"",
`Runs in the foreground. ${command} web is an alias.`,
`Runs in the foreground by default. ${command} web is an alias.`,
"",
"Options:",
" --daemon Start the management server in the background instead of the foreground.",
" --host <host> Management server host. Defaults to CCR_WEB_HOST or 127.0.0.1.",
" --port <port> Management server port. Defaults to CCR_WEB_PORT or 3458.",
" --open Open the management page in the default browser.",

View file

@ -34,6 +34,18 @@ test("every service command exposes its package-owned command help", () => {
}
});
test("built CLI accepts --daemon on service commands", () => {
for (const args of [
["start", "--daemon", "--help"],
["ui", "--daemon", "--help"],
["serve", "--daemon", "--help"]
]) {
const result = runCli(args);
assert.equal(result.status, 0, `${args.join(" ")}: ${result.stderr}`);
assert.match(result.stdout, /--daemon/, args.join(" "));
}
});
test("built CLI rejects missing, out-of-range, and unknown service options", () => {
const cases = [
[["serve", "--host"], /--host requires a value/],