237 lines
7.2 KiB
Python
Executable File
237 lines
7.2 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""
|
|
Multi-Agent Pipeline: Plan Agent Launcher.
|
|
|
|
Usage: python3 plan.py --name <task-name> --type <dev-type> --requirement "<requirement>"
|
|
|
|
This script:
|
|
1. Creates task directory
|
|
2. Starts Plan Agent in background
|
|
3. Plan Agent produces fully configured task directory
|
|
|
|
After completion, use start.py to launch the Dispatch Agent.
|
|
|
|
Prerequisites:
|
|
- agents/plan.md must exist (in .claude/, .cursor/, .iflow/, or .opencode/)
|
|
- Developer must be initialized
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add parent directory to path for imports
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from common.cli_adapter import get_cli_adapter
|
|
from common.paths import get_repo_root
|
|
from common.developer import ensure_developer
|
|
|
|
|
|
# =============================================================================
|
|
# Colors
|
|
# =============================================================================
|
|
|
|
class Colors:
|
|
RED = "\033[0;31m"
|
|
GREEN = "\033[0;32m"
|
|
YELLOW = "\033[1;33m"
|
|
BLUE = "\033[0;34m"
|
|
NC = "\033[0m"
|
|
|
|
|
|
def log_info(msg: str) -> None:
|
|
print(f"{Colors.BLUE}[INFO]{Colors.NC} {msg}")
|
|
|
|
|
|
def log_success(msg: str) -> None:
|
|
print(f"{Colors.GREEN}[SUCCESS]{Colors.NC} {msg}")
|
|
|
|
|
|
def log_error(msg: str) -> None:
|
|
print(f"{Colors.RED}[ERROR]{Colors.NC} {msg}")
|
|
|
|
|
|
# =============================================================================
|
|
# Constants
|
|
# =============================================================================
|
|
|
|
DEFAULT_PLATFORM = "claude"
|
|
|
|
|
|
# =============================================================================
|
|
# Main
|
|
# =============================================================================
|
|
|
|
def main() -> int:
|
|
"""Main entry point."""
|
|
parser = argparse.ArgumentParser(
|
|
description="Multi-Agent Pipeline: Plan Agent Launcher"
|
|
)
|
|
parser.add_argument("--name", "-n", required=True, help="Task name (e.g., user-auth)")
|
|
parser.add_argument("--type", "-t", required=True, help="Dev type: backend|frontend|fullstack")
|
|
parser.add_argument("--requirement", "-r", required=True, help="Requirement description")
|
|
parser.add_argument(
|
|
"--platform", "-p",
|
|
choices=["claude", "cursor", "iflow", "opencode", "qoder"],
|
|
default=DEFAULT_PLATFORM,
|
|
help="Platform to use (default: claude)"
|
|
)
|
|
|
|
args = parser.parse_args()
|
|
|
|
task_name = args.name
|
|
dev_type = args.type
|
|
requirement = args.requirement
|
|
platform = args.platform
|
|
|
|
# Initialize CLI adapter
|
|
adapter = get_cli_adapter(platform)
|
|
|
|
# Validate dev type
|
|
if dev_type not in ("backend", "frontend", "fullstack"):
|
|
log_error(f"Invalid dev type: {dev_type} (must be: backend, frontend, fullstack)")
|
|
return 1
|
|
|
|
project_root = get_repo_root()
|
|
|
|
# Check plan agent exists (path varies by platform)
|
|
plan_md = adapter.get_agent_path("plan", project_root)
|
|
if not plan_md.is_file():
|
|
log_error(f"plan agent not found at {plan_md}")
|
|
log_info(f"Platform: {platform}")
|
|
return 1
|
|
|
|
ensure_developer(project_root)
|
|
|
|
# =============================================================================
|
|
# Step 1: Create Task Directory
|
|
# =============================================================================
|
|
print()
|
|
print(f"{Colors.BLUE}=== Multi-Agent Pipeline: Plan ==={Colors.NC}")
|
|
log_info(f"Task: {task_name}")
|
|
log_info(f"Type: {dev_type}")
|
|
log_info(f"Requirement: {requirement}")
|
|
print()
|
|
|
|
log_info("Step 1: Creating task directory...")
|
|
|
|
# Import task module to create task
|
|
from task import cmd_create
|
|
import argparse as ap
|
|
|
|
# Create task using task.py's create command
|
|
create_args = ap.Namespace(
|
|
title=requirement,
|
|
slug=task_name,
|
|
assignee=None,
|
|
priority="P2",
|
|
description=""
|
|
)
|
|
|
|
# Capture stdout to get task dir
|
|
import io
|
|
from contextlib import redirect_stdout
|
|
|
|
stdout_capture = io.StringIO()
|
|
with redirect_stdout(stdout_capture):
|
|
ret = cmd_create(create_args)
|
|
|
|
if ret != 0:
|
|
log_error("Failed to create task directory")
|
|
return 1
|
|
|
|
task_dir = stdout_capture.getvalue().strip().split("\n")[-1]
|
|
task_dir_abs = project_root / task_dir
|
|
|
|
log_success(f"Task directory: {task_dir}")
|
|
|
|
# =============================================================================
|
|
# Step 2: Prepare and Start Plan Agent
|
|
# =============================================================================
|
|
log_info("Step 2: Starting Plan Agent in background...")
|
|
|
|
log_file = task_dir_abs / ".plan-log"
|
|
log_file.touch()
|
|
|
|
# Get proxy environment variables
|
|
https_proxy = os.environ.get("https_proxy", "")
|
|
http_proxy = os.environ.get("http_proxy", "")
|
|
all_proxy = os.environ.get("all_proxy", "")
|
|
|
|
# Start agent in background (cross-platform, no shell script needed)
|
|
env = os.environ.copy()
|
|
env["PLAN_TASK_NAME"] = task_name
|
|
env["PLAN_DEV_TYPE"] = dev_type
|
|
env["PLAN_TASK_DIR"] = task_dir
|
|
env["PLAN_REQUIREMENT"] = requirement
|
|
env["https_proxy"] = https_proxy
|
|
env["http_proxy"] = http_proxy
|
|
env["all_proxy"] = all_proxy
|
|
|
|
# Clear nested-session detection so the new CLI process can start
|
|
env.pop("CLAUDECODE", None)
|
|
|
|
# Set non-interactive env var based on platform
|
|
env.update(adapter.get_non_interactive_env())
|
|
|
|
# Build CLI command using adapter
|
|
cli_cmd = adapter.build_run_command(
|
|
agent="plan", # Will be mapped to "trellis-plan" for OpenCode
|
|
prompt=f"Start planning for task: {task_name}",
|
|
skip_permissions=True,
|
|
verbose=True,
|
|
json_output=True,
|
|
)
|
|
|
|
with log_file.open("w") as log_f:
|
|
# Use shell=False for cross-platform compatibility
|
|
# creationflags for Windows, start_new_session for Unix
|
|
popen_kwargs = {
|
|
"stdout": log_f,
|
|
"stderr": subprocess.STDOUT,
|
|
"cwd": str(project_root),
|
|
"env": env,
|
|
}
|
|
if sys.platform == "win32":
|
|
popen_kwargs["creationflags"] = subprocess.CREATE_NEW_PROCESS_GROUP
|
|
else:
|
|
popen_kwargs["start_new_session"] = True
|
|
|
|
process = subprocess.Popen(cli_cmd, **popen_kwargs)
|
|
agent_pid = process.pid
|
|
|
|
log_success(f"Plan Agent started (PID: {agent_pid})")
|
|
|
|
# =============================================================================
|
|
# Summary
|
|
# =============================================================================
|
|
print()
|
|
print(f"{Colors.GREEN}=== Plan Agent Running ==={Colors.NC}")
|
|
print()
|
|
print(f" Task: {task_name}")
|
|
print(f" Type: {dev_type}")
|
|
print(f" Dir: {task_dir}")
|
|
print(f" Log: {log_file}")
|
|
print(f" PID: {agent_pid}")
|
|
print()
|
|
print(f"{Colors.YELLOW}To monitor:{Colors.NC}")
|
|
print(f" tail -f {log_file}")
|
|
print()
|
|
print(f"{Colors.YELLOW}To check status:{Colors.NC}")
|
|
print(f" ps -p {agent_pid}")
|
|
print(f" ls -la {task_dir}")
|
|
print()
|
|
print(f"{Colors.YELLOW}After completion, run:{Colors.NC}")
|
|
print(f" python3 ./.trellis/scripts/multi_agent/start.py {task_dir}")
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|