forked from mengyxu/noob-components
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
6.7 KiB
213 lines
6.7 KiB
#!/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 |
|
|
|
import _bootstrap # noqa: F401 — adds parent scripts/ dir to sys.path |
|
|
|
from common.cli_adapter import get_cli_adapter |
|
from common.log import Colors, log_info, log_success, log_error |
|
from common.paths import get_repo_root |
|
from common.developer import ensure_developer |
|
|
|
|
|
# ============================================================================= |
|
# 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", "codex", "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) |
|
if adapter.requires_agent_definition_file: |
|
plan_md = adapter.get_agent_path("plan", project_root) |
|
if not plan_md.is_file(): |
|
log_error(f"Agent definition 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())
|
|
|