feat(cli): add clean analysis export with markdown/json output

This commit is contained in:
zphinx
2026-05-11 21:54:21 +02:00
parent 92ce7da28f
commit 2d8a5a66ca
7 changed files with 206 additions and 7 deletions

View File

@@ -1,3 +1,4 @@
import json
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock
@@ -444,3 +445,105 @@ def test_interactive_history_without_store_shows_hint(monkeypatch) -> None: # t
assert result.exit_code == 0
assert "Session memory is disabled" in result.stdout
def test_run_analyze_writes_output_file(monkeypatch, tmp_path: Path) -> None: # type: ignore[no-untyped-def]
_mock_session(monkeypatch)
async def fake_collect_from_plan(_session, _plan) -> CollectionReport: # type: ignore[no-untyped-def]
return CollectionReport(
host="ssh.archflux.net",
items=[
CollectedItem(
name="kernel",
result=SSHCommandResult(
command="uname -a",
exit_code=0,
stdout="Linux test",
stderr="",
),
),
],
)
monkeypatch.setattr("tai.cli.collect_from_plan", fake_collect_from_plan)
monkeypatch.setattr(
"tai.cli.AIClient.complete",
lambda *_args, **_kwargs: SimpleNamespace(content="Root Cause\n\nEvidence\n\nRecommended Actions"),
)
output_path = tmp_path / "analysis.md"
runner = CliRunner()
result = runner.invoke(
app,
[
"run", "apache failed",
"--host",
"ssh.archflux.net",
"--port",
"5566",
"--no-probe",
"--analyze",
"--output-file",
str(output_path),
],
)
assert result.exit_code == 0
assert "Wrote analysis output" in result.stdout
assert output_path.exists()
assert "Root Cause" in output_path.read_text(encoding="utf-8")
def test_run_analyze_writes_json_output_and_strips_ansi(monkeypatch, tmp_path: Path) -> None: # type: ignore[no-untyped-def]
_mock_session(monkeypatch)
async def fake_collect_from_plan(_session, _plan) -> CollectionReport: # type: ignore[no-untyped-def]
return CollectionReport(
host="ssh.archflux.net",
items=[
CollectedItem(
name="kernel",
result=SSHCommandResult(
command="uname -a",
exit_code=0,
stdout="Linux test",
stderr="",
),
),
],
)
monkeypatch.setattr("tai.cli.collect_from_plan", fake_collect_from_plan)
monkeypatch.setattr(
"tai.cli.AIClient.complete",
lambda *_args, **_kwargs: SimpleNamespace(
content="\x1b[31mRoot Cause\x1b[0m\n\nEvidence\n\nRecommended Actions"
),
)
output_path = tmp_path / "analysis.json"
runner = CliRunner()
result = runner.invoke(
app,
[
"run", "apache failed",
"--host",
"ssh.archflux.net",
"--port",
"5566",
"--no-probe",
"--analyze",
"--output-file",
str(output_path),
"--output-format",
"json",
],
)
assert result.exit_code == 0
payload = json.loads(output_path.read_text(encoding="utf-8"))
assert payload["issue"] == "apache failed"
assert payload["host"] == "ssh.archflux.net"
assert "Root Cause" in payload["analysis"]
assert "\u001b" not in payload["analysis"]