kin: KIN-016 Агенты должны уметь говорить 'не могу'. Если агент не может выполнить задачу (нет доступа, не понимает, выходит за компетенцию) — он должен вернуть status: blocked с причиной, а не пытаться угадывать. PM при получении blocked от агента — эскалирует к человеку через GUI (уведомление) и Telegram (когда будет).
This commit is contained in:
parent
a605e9d110
commit
d9172fc17c
35 changed files with 2375 additions and 23 deletions
68
cli/main.py
68
cli/main.py
|
|
@ -96,6 +96,74 @@ def project_add(ctx, id, name, path, tech_stack, status, priority, language):
|
|||
click.echo(f"Created project: {p['id']} ({p['name']})")
|
||||
|
||||
|
||||
@cli.command("new-project")
|
||||
@click.argument("description")
|
||||
@click.option("--id", "project_id", required=True, help="Project ID")
|
||||
@click.option("--name", required=True, help="Project name")
|
||||
@click.option("--path", required=True, help="Project path")
|
||||
@click.option("--roles", default="business,market,tech", show_default=True,
|
||||
help="Comma-separated roles: business,market,legal,tech,ux,marketer")
|
||||
@click.option("--tech-stack", default=None, help="Comma-separated tech stack")
|
||||
@click.option("--priority", type=int, default=5, show_default=True)
|
||||
@click.option("--language", default="ru", show_default=True)
|
||||
@click.pass_context
|
||||
def new_project(ctx, description, project_id, name, path, roles, tech_stack, priority, language):
|
||||
"""Create a new project with a sequential research phase pipeline.
|
||||
|
||||
DESCRIPTION — free-text project description for the agents.
|
||||
|
||||
Role aliases: business=business_analyst, market=market_researcher,
|
||||
legal=legal_researcher, tech=tech_researcher, ux=ux_designer, marketer=marketer.
|
||||
Architect is added automatically as the last phase.
|
||||
"""
|
||||
from core.phases import create_project_with_phases, validate_roles, ROLE_LABELS
|
||||
|
||||
_ALIASES = {
|
||||
"business": "business_analyst",
|
||||
"market": "market_researcher",
|
||||
"legal": "legal_researcher",
|
||||
"tech": "tech_researcher",
|
||||
"ux": "ux_designer",
|
||||
}
|
||||
|
||||
raw_roles = [r.strip().lower() for r in roles.split(",") if r.strip()]
|
||||
expanded = [_ALIASES.get(r, r) for r in raw_roles]
|
||||
clean_roles = validate_roles(expanded)
|
||||
if not clean_roles:
|
||||
click.echo("Error: no valid research roles specified.", err=True)
|
||||
raise SystemExit(1)
|
||||
|
||||
ts = [s.strip() for s in tech_stack.split(",") if s.strip()] if tech_stack else None
|
||||
conn = ctx.obj["conn"]
|
||||
|
||||
if models.get_project(conn, project_id):
|
||||
click.echo(f"Error: project '{project_id}' already exists.", err=True)
|
||||
raise SystemExit(1)
|
||||
|
||||
try:
|
||||
result = create_project_with_phases(
|
||||
conn, project_id, name, path,
|
||||
description=description,
|
||||
selected_roles=clean_roles,
|
||||
tech_stack=ts,
|
||||
priority=priority,
|
||||
language=language,
|
||||
)
|
||||
except ValueError as e:
|
||||
click.echo(f"Error: {e}", err=True)
|
||||
raise SystemExit(1)
|
||||
|
||||
click.echo(f"Created project: {result['project']['id']} ({result['project']['name']})")
|
||||
click.echo(f"Description: {description}")
|
||||
click.echo("")
|
||||
phases = result["phases"]
|
||||
rows = [
|
||||
[str(p["id"]), str(p["phase_order"] + 1), p["role"], p["status"], p.get("task_id") or "—"]
|
||||
for p in phases
|
||||
]
|
||||
click.echo(_table(["ID", "#", "Role", "Status", "Task"], rows))
|
||||
|
||||
|
||||
@project.command("list")
|
||||
@click.option("--status", default=None)
|
||||
@click.pass_context
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue