feat: terminal launcher diagnostics and mutation preflight (Closes #556)
Add categorize-and-probe helpers for shell spawn failures, expose gitea_diagnose_terminal, and fail closed on mutation capability resolve when the terminal launcher is unhealthy (BLOCKED + DIAGNOSE). Document the operator path in the workflow runbooks.
This commit is contained in:
@@ -7906,6 +7906,36 @@ def gitea_get_shell_health() -> dict:
|
||||
return native_mcp_preference.shell_health_status()
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def gitea_diagnose_terminal(
|
||||
cwd: str | None = None,
|
||||
command: list[str] | None = None,
|
||||
) -> dict:
|
||||
"""Read-only: Run active diagnostics on terminal launcher spawn ability (#556).
|
||||
|
||||
Args:
|
||||
cwd: Active worktree or current directory to test (defaults to GITEA_ACTIVE_WORKTREE).
|
||||
command: Test command to attempt (defaults to ['git', '--version'] or ['echo', 'ok']).
|
||||
"""
|
||||
resolved_cwd = cwd or os.environ.get("GITEA_ACTIVE_WORKTREE")
|
||||
if resolved_cwd:
|
||||
resolved_cwd = os.path.realpath(resolved_cwd)
|
||||
|
||||
probe_cmd = command or native_mcp_preference.default_terminal_probe_command()
|
||||
|
||||
diag = native_mcp_preference.diagnose_terminal_failure(resolved_cwd, probe_cmd)
|
||||
probe_res = native_mcp_preference.probe_terminal_spawn(resolved_cwd, probe_cmd)
|
||||
|
||||
return {
|
||||
"healthy": probe_res["healthy"],
|
||||
"error_type": None if probe_res["healthy"] else probe_res["error_type"] or diag["error_type"],
|
||||
"error_msg": "" if probe_res["healthy"] else probe_res["error_msg"] or diag["error_msg"],
|
||||
"cwd": resolved_cwd,
|
||||
"command": probe_cmd,
|
||||
"diagnostics": diag,
|
||||
}
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def gitea_validate_review_final_report(
|
||||
report_text: str,
|
||||
@@ -9412,6 +9442,43 @@ def gitea_resolve_task_capability(
|
||||
"exact_safe_next_action": next_safe_action,
|
||||
}
|
||||
|
||||
# ── Terminal Launcher Preflight Check (#556) ──
|
||||
if task in native_mcp_preference.GITEA_MUTATION_TASKS:
|
||||
in_test = _preflight_in_test_mode()
|
||||
if not in_test or os.environ.get("GITEA_FORCE_TERMINAL_PROBE") == "1":
|
||||
resolved_cwd = os.environ.get("GITEA_ACTIVE_WORKTREE") or PROJECT_ROOT
|
||||
probe_res = native_mcp_preference.probe_terminal_spawn(resolved_cwd)
|
||||
if not probe_res["healthy"]:
|
||||
profile = get_profile()
|
||||
h = host or (REMOTES.get(remote, {}).get("host") if remote in REMOTES else None)
|
||||
username = _authenticated_username(h) if h else None
|
||||
next_safe_action = (
|
||||
"BLOCKED + DIAGNOSE: terminal-launcher-failure "
|
||||
f"({probe_res['error_type']}): {probe_res['error_msg']}. "
|
||||
"Do not attempt git/pytest finalization or unsafe fallbacks. "
|
||||
"Run gitea_diagnose_terminal, emit blocked-diagnose-report, and stop."
|
||||
)
|
||||
return {
|
||||
"requested_task": task,
|
||||
"required_operation_permission": required_permission,
|
||||
"required_role_kind": required_role,
|
||||
"active_profile": profile["profile_name"],
|
||||
"active_identity": username,
|
||||
"active_profile_allowed_operations": profile.get("allowed_operations") or [],
|
||||
"allowed_in_current_session": False,
|
||||
"stop_required": True,
|
||||
"infra_stop": True,
|
||||
"blocked": True,
|
||||
"blocked_reason": "BLOCKED + DIAGNOSE",
|
||||
"terminal_launcher_unhealthy": True,
|
||||
"terminal_launcher_diagnostics": probe_res,
|
||||
"task_role_guidance": [next_safe_action],
|
||||
"matching_configured_profile": [],
|
||||
"runtime_switching_supported": gitea_config.is_runtime_switching_enabled(),
|
||||
"different_mcp_namespace_required": False,
|
||||
"exact_safe_next_action": next_safe_action,
|
||||
}
|
||||
|
||||
record_preflight_check("capability", required_role, resolved_task=task)
|
||||
|
||||
# Try automatic dispatch switching
|
||||
|
||||
Reference in New Issue
Block a user