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 <noreply@anthropic.com>
This commit is contained in:
suraj-markup 2026-03-01 18:47:09 +05:30
parent 4cda43795b
commit 5f9481bc01
1 changed files with 26 additions and 6 deletions

View File

@ -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<number> {
/** Find the first available port starting from `start`, scanning upward. Returns `null` if none found. */
async function findFreePort(start: number): Promise<number | null> {
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<string, unknown> = {
name: projectId,
sessionPrefix: projectId.slice(0, 8),
repo,
path: projectPath,
defaultBranch,
@ -444,10 +454,18 @@ async function handleAutoMode(outputPath: string, smart: boolean): Promise<void>
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<string, unknown> = {
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<void>
},
projects: {
[projectId]: {
name: projectId,
sessionPrefix: projectId.slice(0, 8),
repo,
path,
defaultBranch,