Add permission-aware follow-up flow with interactive resolution
When follow-up agent detects permission-blocked items ("ручное
применение", "permission denied", etc.), they become pending_actions
instead of auto-created tasks. User chooses per item:
1. Rerun with --dangerously-skip-permissions
2. Create manual task
3. Skip
core/followup.py:
_is_permission_blocked() — regex detection of 9 permission patterns
generate_followups() returns {created, pending_actions}
resolve_pending_action() — handles rerun/manual_task/skip
agents/runner.py:
_run_claude(allow_write=True) adds --dangerously-skip-permissions
run_agent/run_pipeline pass allow_write through
CLI: kin approve --followup — interactive 1/2/3 prompt per blocked item
API: POST /approve returns {needs_decision, pending_actions}
POST /resolve resolves individual actions
Frontend: pending actions shown as cards with 3 buttons in approve modal
136 tests, all passing. Frontend builds clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9264415776
commit
ab693d3c4d
7 changed files with 356 additions and 73 deletions
30
cli/main.py
30
cli/main.py
|
|
@ -421,7 +421,7 @@ def cost(ctx, period):
|
|||
@click.pass_context
|
||||
def approve_task(ctx, task_id, followup, decision_text):
|
||||
"""Approve a task (set status=done). Optionally generate follow-ups."""
|
||||
from core.followup import generate_followups
|
||||
from core.followup import generate_followups, resolve_pending_action
|
||||
|
||||
conn = ctx.obj["conn"]
|
||||
task = models.get_task(conn, task_id)
|
||||
|
|
@ -441,12 +441,36 @@ def approve_task(ctx, task_id, followup, decision_text):
|
|||
|
||||
if followup:
|
||||
click.echo("Generating follow-up tasks...")
|
||||
created = generate_followups(conn, task_id)
|
||||
result = generate_followups(conn, task_id)
|
||||
created = result["created"]
|
||||
pending = result["pending_actions"]
|
||||
|
||||
if created:
|
||||
click.echo(f"Created {len(created)} follow-up tasks:")
|
||||
for t in created:
|
||||
click.echo(f" {t['id']}: {t['title']} (pri {t['priority']})")
|
||||
else:
|
||||
|
||||
for action in pending:
|
||||
click.echo(f"\nPermission issue: {action['description']}")
|
||||
click.echo(" 1. Rerun with --dangerously-skip-permissions")
|
||||
click.echo(" 2. Create task for manual fix")
|
||||
click.echo(" 3. Skip")
|
||||
choice_input = click.prompt("Choice", type=click.Choice(["1", "2", "3"]), default="2")
|
||||
choice_map = {"1": "rerun", "2": "manual_task", "3": "skip"}
|
||||
choice = choice_map[choice_input]
|
||||
result = resolve_pending_action(conn, task_id, action, choice)
|
||||
if choice == "rerun" and result:
|
||||
rr = result.get("rerun_result", {})
|
||||
if rr.get("success"):
|
||||
click.echo(" Re-run completed successfully.")
|
||||
else:
|
||||
click.echo(f" Re-run failed: {rr.get('error', 'unknown')}")
|
||||
elif choice == "manual_task" and result:
|
||||
click.echo(f" Created: {result['id']}: {result['title']}")
|
||||
elif choice == "skip":
|
||||
click.echo(" Skipped.")
|
||||
|
||||
if not created and not pending:
|
||||
click.echo("No follow-up tasks generated.")
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue