fix(setup): improve setup.sh with prereq validation and add ao start/spawn pre-flight checks
- Rewrite setup.sh with hard stops for Node<20 and git<2.25, soft warns with interactive fix for tmux/gh-auth/claude, corepack-based pnpm install, and PATH verification after npm link - Add pre-flight checks to `ao start`: verify dashboard port is free and packages are built before proceeding - Add pre-flight checks to `ao spawn`: verify tmux is installed and gh is authenticated (when using github tracker) before session creation - Extract shared preflight utilities into packages/cli/src/lib/preflight.ts Closes #245 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
4cda43795b
commit
e40275b53c
|
|
@ -5,6 +5,7 @@ import { loadConfig, type OrchestratorConfig } from "@composio/ao-core";
|
|||
import { exec } from "../lib/shell.js";
|
||||
import { banner } from "../lib/format.js";
|
||||
import { getSessionManager } from "../lib/create-session-manager.js";
|
||||
import { preflight } from "../lib/preflight.js";
|
||||
|
||||
async function spawnSession(
|
||||
config: OrchestratorConfig,
|
||||
|
|
@ -13,6 +14,15 @@ async function spawnSession(
|
|||
openTab?: boolean,
|
||||
agent?: string,
|
||||
): Promise<string> {
|
||||
// Pre-flight: ensure tmux is available (default runtime)
|
||||
await preflight.checkTmux();
|
||||
|
||||
// Pre-flight: ensure gh is authenticated if using github tracker
|
||||
const project = config.projects[projectId];
|
||||
if (project?.tracker?.plugin === "github") {
|
||||
await preflight.checkGhAuth();
|
||||
}
|
||||
|
||||
const spinner = ora("Creating session").start();
|
||||
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { exec } from "../lib/shell.js";
|
|||
import { getSessionManager } from "../lib/create-session-manager.js";
|
||||
import { findWebDir, buildDashboardEnv } from "../lib/web-dir.js";
|
||||
import { cleanNextCache } from "../lib/dashboard-rebuild.js";
|
||||
import { preflight } from "../lib/preflight.js";
|
||||
|
||||
/**
|
||||
* Resolve project from config.
|
||||
|
|
@ -138,6 +139,10 @@ export function registerStart(program: Command): void {
|
|||
const sessionId = `${project.sessionPrefix}-orchestrator`;
|
||||
const port = config.port ?? 3000;
|
||||
|
||||
// Pre-flight checks
|
||||
await preflight.checkPort(port);
|
||||
await preflight.checkBuilt();
|
||||
|
||||
console.log(chalk.bold(`\nStarting orchestrator for ${chalk.cyan(project.name)}\n`));
|
||||
|
||||
// Start dashboard (unless --no-dashboard)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,73 @@
|
|||
/**
|
||||
* Pre-flight checks for `ao start` and `ao spawn`.
|
||||
*
|
||||
* Validates runtime prerequisites before entering the main command flow,
|
||||
* giving clear errors instead of cryptic failures.
|
||||
*/
|
||||
|
||||
import { existsSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import chalk from "chalk";
|
||||
import { isPortAvailable, findWebDir } from "./web-dir.js";
|
||||
import { exec } from "./shell.js";
|
||||
|
||||
/**
|
||||
* Check that the dashboard port is free.
|
||||
* Exits with a clear message if it's already in use.
|
||||
*/
|
||||
async function checkPort(port: number): Promise<void> {
|
||||
const free = await isPortAvailable(port);
|
||||
if (!free) {
|
||||
console.error(
|
||||
chalk.red(
|
||||
`Port ${port} is already in use. Free it or change 'port' in agent-orchestrator.yaml.`,
|
||||
),
|
||||
);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that packages have been built (the web .next directory exists).
|
||||
* Exits with a clear message if not.
|
||||
*/
|
||||
async function checkBuilt(): Promise<void> {
|
||||
const webDir = findWebDir();
|
||||
const buildId = resolve(webDir, ".next", "BUILD_ID");
|
||||
if (!existsSync(buildId)) {
|
||||
console.error(chalk.red("Packages not built. Run: pnpm build"));
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that tmux is installed (required for the default runtime).
|
||||
* Throws with a clear message if not.
|
||||
*/
|
||||
async function checkTmux(): Promise<void> {
|
||||
try {
|
||||
await exec("tmux", ["-V"]);
|
||||
} catch {
|
||||
throw new Error("tmux is not installed. Install it: brew install tmux");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the GitHub CLI is authenticated.
|
||||
* Only relevant when the project uses the github tracker plugin.
|
||||
* Throws with a clear message if not authenticated.
|
||||
*/
|
||||
async function checkGhAuth(): Promise<void> {
|
||||
try {
|
||||
await exec("gh", ["auth", "status"]);
|
||||
} catch {
|
||||
throw new Error("GitHub CLI is not authenticated. Run: gh auth login");
|
||||
}
|
||||
}
|
||||
|
||||
export const preflight = {
|
||||
checkPort,
|
||||
checkBuilt,
|
||||
checkTmux,
|
||||
checkGhAuth,
|
||||
};
|
||||
141
scripts/setup.sh
141
scripts/setup.sh
|
|
@ -1,38 +1,149 @@
|
|||
#!/bin/bash
|
||||
# Agent Orchestrator setup script
|
||||
# Installs dependencies, builds packages, and links the CLI globally
|
||||
# Validates prerequisites, installs dependencies, builds packages, and links the CLI globally
|
||||
|
||||
set -e # Exit on error
|
||||
|
||||
echo "🤖 Agent Orchestrator Setup"
|
||||
REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
|
||||
echo "Agent Orchestrator Setup"
|
||||
echo ""
|
||||
|
||||
# Check for pnpm
|
||||
if ! command -v pnpm &> /dev/null; then
|
||||
echo "❌ pnpm not found. Installing pnpm..."
|
||||
npm install -g pnpm
|
||||
# ─── Hard requirements (exit 1 if missing) ────────────────────────────────────
|
||||
|
||||
# Node.js >= 20
|
||||
if ! command -v node &> /dev/null; then
|
||||
echo "ERROR: Node.js is not installed."
|
||||
echo " Install Node.js 20+: https://nodejs.org/en/download"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📦 Installing dependencies..."
|
||||
NODE_MAJOR=$(node -e "process.stdout.write(String(process.versions.node.split('.')[0]))")
|
||||
if [ "$NODE_MAJOR" -lt 20 ]; then
|
||||
echo "ERROR: Node.js $NODE_MAJOR.x detected, but 20+ is required."
|
||||
echo " Install Node.js 20+: https://nodejs.org/en/download"
|
||||
exit 1
|
||||
fi
|
||||
echo "[ok] Node.js $(node --version)"
|
||||
|
||||
# git >= 2.25 (required for worktree support)
|
||||
if ! command -v git &> /dev/null; then
|
||||
echo "ERROR: git is not installed."
|
||||
echo " Install git 2.25+: https://git-scm.com/downloads"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GIT_VERSION=$(git --version | grep -oE '[0-9]+\.[0-9]+' | head -1)
|
||||
GIT_MAJOR=$(echo "$GIT_VERSION" | cut -d. -f1)
|
||||
GIT_MINOR=$(echo "$GIT_VERSION" | cut -d. -f2)
|
||||
if [ "$GIT_MAJOR" -lt 2 ] || { [ "$GIT_MAJOR" -eq 2 ] && [ "$GIT_MINOR" -lt 25 ]; }; then
|
||||
echo "ERROR: git $GIT_VERSION detected, but 2.25+ is required (worktree support)."
|
||||
echo " Upgrade git: https://git-scm.com/downloads"
|
||||
exit 1
|
||||
fi
|
||||
echo "[ok] git $GIT_VERSION"
|
||||
|
||||
# ─── Soft requirements (warn + offer interactive fix) ─────────────────────────
|
||||
|
||||
# tmux
|
||||
if ! command -v tmux &> /dev/null; then
|
||||
echo ""
|
||||
echo "WARNING: tmux is not installed (default runtime requires it)."
|
||||
if command -v brew &> /dev/null; then
|
||||
read -r -p " Install tmux via Homebrew? [Y/n] " response
|
||||
response=${response:-Y}
|
||||
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||
brew install tmux
|
||||
echo "[ok] tmux installed"
|
||||
else
|
||||
echo " Skipping. Install later: brew install tmux"
|
||||
fi
|
||||
else
|
||||
echo " Install tmux: https://github.com/tmux/tmux/wiki/Installing"
|
||||
fi
|
||||
else
|
||||
echo "[ok] tmux $(tmux -V | grep -oE '[0-9]+\.[0-9a-z]+')"
|
||||
fi
|
||||
|
||||
# gh CLI authentication
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo ""
|
||||
echo "WARNING: GitHub CLI (gh) is not installed."
|
||||
echo " Install: https://cli.github.com/"
|
||||
else
|
||||
if ! gh auth status &> /dev/null; then
|
||||
echo ""
|
||||
echo "WARNING: GitHub CLI is not authenticated."
|
||||
read -r -p " Run 'gh auth login' now? [Y/n] " response
|
||||
response=${response:-Y}
|
||||
if [[ "$response" =~ ^[Yy]$ ]]; then
|
||||
gh auth login
|
||||
else
|
||||
echo " Skipping. Authenticate later: gh auth login"
|
||||
fi
|
||||
else
|
||||
echo "[ok] gh authenticated"
|
||||
fi
|
||||
fi
|
||||
|
||||
# claude CLI
|
||||
if ! command -v claude &> /dev/null; then
|
||||
echo ""
|
||||
echo "WARNING: Claude CLI is not installed (required for claude-code agent)."
|
||||
echo " Install: npm install -g @anthropic-ai/claude-code"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
|
||||
# ─── Install pnpm via corepack ───────────────────────────────────────────────
|
||||
|
||||
echo "Enabling corepack and preparing pnpm..."
|
||||
corepack enable
|
||||
corepack prepare --activate
|
||||
echo "[ok] pnpm $(pnpm --version)"
|
||||
|
||||
# ─── Install, build, link ────────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "Installing dependencies..."
|
||||
pnpm install
|
||||
|
||||
echo "🧹 Cleaning stale build artifacts..."
|
||||
echo ""
|
||||
echo "Cleaning stale build artifacts..."
|
||||
rm -rf packages/web/.next
|
||||
|
||||
echo "🔨 Building all packages..."
|
||||
echo ""
|
||||
echo "Building all packages..."
|
||||
pnpm build
|
||||
|
||||
echo "🔗 Linking CLI globally..."
|
||||
echo ""
|
||||
echo "Linking CLI globally..."
|
||||
cd packages/cli
|
||||
npm link
|
||||
cd ../..
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# ─── Verify ao is in PATH ────────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "✅ Setup complete! The 'ao' command is now available."
|
||||
if command -v ao &> /dev/null; then
|
||||
echo "[ok] 'ao' command is available in PATH"
|
||||
else
|
||||
NPM_BIN="$(npm bin -g 2>/dev/null || npm config get prefix)/bin"
|
||||
echo "WARNING: 'ao' is not in your PATH."
|
||||
echo " Add this to your shell profile (~/.zshrc or ~/.bashrc):"
|
||||
echo ""
|
||||
echo " export PATH=\"$NPM_BIN:\$PATH\""
|
||||
echo ""
|
||||
echo " Then restart your terminal or run: source ~/.zshrc"
|
||||
fi
|
||||
|
||||
# ─── Done ─────────────────────────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "Setup complete!"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo " 1. cd /path/to/your/project"
|
||||
echo " 1. cd /path/to/your-project"
|
||||
echo " 2. ao init --auto"
|
||||
echo " 3. gh auth login"
|
||||
echo " 4. ao start"
|
||||
echo " 3. ao start"
|
||||
echo ""
|
||||
|
|
|
|||
Loading…
Reference in New Issue