From 5f9481bc0148558098cc5ac7e32ac8caf9f19e09 Mon Sep 17 00:00:00 2001 From: suraj-markup Date: Sun, 1 Mar 2026 18:47:09 +0530 Subject: [PATCH] fix(cli): add missing sessionPrefix, name, and port validation in ao init - Add `sessionPrefix` (derived from projectId.slice(0, 8)) to project config in both interactive and auto modes so session IDs are valid instead of `undefined-1` - Add `name` field to project config so `ao start` prints the actual project name instead of "undefined" - Mark `--smart` flag as "(coming soon)" in help text since it is a no-op stub - Return `null` from `findFreePort` when no port is available and warn the user to set the port manually Closes #236 Co-Authored-By: Claude Opus 4.6 --- packages/cli/src/commands/init.ts | 32 +++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 17c54e256..d11f5d424 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -16,12 +16,12 @@ import { const DEFAULT_PORT = 3000; const MAX_PORT_SCAN = 100; -/** Find the first available port starting from `start`, scanning upward. */ -async function findFreePort(start: number): Promise { +/** Find the first available port starting from `start`, scanning upward. Returns `null` if none found. */ +async function findFreePort(start: number): Promise { for (let port = start; port < start + MAX_PORT_SCAN; port++) { if (await isPortAvailable(port)) return port; } - return start; // fallback — will fail at bind time with a clear error + return null; } async function prompt( @@ -157,7 +157,7 @@ export function registerInit(program: Command): void { .option("--auto", "Auto-generate config with sensible defaults (no prompts)") .option( "--smart", - "Analyze project and generate custom rules (requires --auto, uses AI if available)", + "Analyze project and generate custom rules (coming soon — requires --auto)", ) .action(async (opts: { output: string; auto?: boolean; smart?: boolean }) => { const outputPath = resolve(opts.output); @@ -244,7 +244,15 @@ export function registerInit(program: Command): void { ); const worktreeDir = await prompt(rl, "Worktree directory", "~/.worktrees"); const freePort = await findFreePort(DEFAULT_PORT); - const portStr = await prompt(rl, "Dashboard port", String(freePort)); + if (freePort === null) { + console.log( + chalk.yellow( + `\n⚠ No free port found in range ${DEFAULT_PORT}–${DEFAULT_PORT + MAX_PORT_SCAN - 1}.`, + ), + ); + console.log(chalk.dim(" Please specify a port manually.\n")); + } + const portStr = await prompt(rl, "Dashboard port", String(freePort ?? DEFAULT_PORT)); const port = parseInt(portStr, 10); if (isNaN(port) || port < 1 || port > 65535) { console.error(chalk.red("\nInvalid port number. Must be 1-65535.")); @@ -303,6 +311,8 @@ export function registerInit(program: Command): void { ); const projectConfig: Record = { + name: projectId, + sessionPrefix: projectId.slice(0, 8), repo, path: projectPath, defaultBranch, @@ -444,10 +454,18 @@ async function handleAutoMode(outputPath: string, smart: boolean): Promise const defaultBranch = env.defaultBranch || "main"; const port = await findFreePort(DEFAULT_PORT); + if (port === null) { + console.log( + chalk.yellow( + ` ⚠ No free port found in range ${DEFAULT_PORT}–${DEFAULT_PORT + MAX_PORT_SCAN - 1}.`, + ), + ); + console.log(chalk.dim(" Set the port manually in the config before running ao start.\n")); + } const config: Record = { dataDir: "~/.agent-orchestrator", worktreeDir: "~/.worktrees", - port, + port: port ?? DEFAULT_PORT, defaults: { runtime: "tmux", agent: "claude-code", @@ -456,6 +474,8 @@ async function handleAutoMode(outputPath: string, smart: boolean): Promise }, projects: { [projectId]: { + name: projectId, + sessionPrefix: projectId.slice(0, 8), repo, path, defaultBranch,