feat: add history UX and expand retention-focused roadmap
Some checks failed
CI / test (push) Failing after 15s

This commit is contained in:
2026-05-11 21:07:39 +02:00
parent 964aee3481
commit 7749a02706
5 changed files with 552 additions and 1 deletions

View File

@@ -1,3 +1,4 @@
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import AsyncMock, MagicMock
@@ -338,3 +339,108 @@ def test_interactive_rag_debug_prints_retrieval_scores(monkeypatch) -> None: #
assert result.exit_code == 0
assert "RAG retrieve:" in result.stdout
def test_history_command_lists_sessions(monkeypatch) -> None: # type: ignore[no-untyped-def]
class FakeStore:
def __init__(self, _path: str) -> None:
pass
def list_recent(self, *, host: str | None = None, limit: int = 20):
del limit
if host == "web01":
return [
SimpleNamespace(
session_id="20260507T120000Z",
host="web01",
issue="nginx down",
summary="Root cause: bad config",
)
]
return []
monkeypatch.setattr("tai.cli.SessionStore", FakeStore)
runner = CliRunner()
result = runner.invoke(
app,
["history", "--session-memory", "~/.tai/sessions", "--host", "web01"],
)
assert result.exit_code == 0
assert "session(s)" in result.stdout
assert "20260507T120000Z" in result.stdout
def test_history_command_exports_markdown(monkeypatch, tmp_path: Path) -> None: # type: ignore[no-untyped-def]
class FakeStore:
def __init__(self, _path: str) -> None:
pass
def list_recent(self, *, host: str | None = None, limit: int = 20):
del host, limit
return [
SimpleNamespace(
session_id="20260507T120000Z",
host="web01",
issue="nginx down",
summary="Root cause: bad config",
)
]
monkeypatch.setattr("tai.cli.SessionStore", FakeStore)
export_path = tmp_path / "history.md"
runner = CliRunner()
result = runner.invoke(
app,
["history", "--session-memory", "~/.tai/sessions", "--export", str(export_path)],
)
assert result.exit_code == 0
assert "Exported" in result.stdout
text = export_path.read_text(encoding="utf-8")
assert "# tai session history" in text
assert "nginx down" in text
def test_interactive_history_without_store_shows_hint(monkeypatch) -> 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="",
),
),
],
)
commands = iter(["/history", "/quit"])
monkeypatch.setattr("tai.cli.collect_from_plan", fake_collect_from_plan)
monkeypatch.setattr("tai.cli.console.input", lambda _prompt: next(commands))
monkeypatch.setattr("tai.cli._stdin_is_tty", lambda: True)
runner = CliRunner()
result = runner.invoke(
app,
[
"run", "apache failed",
"--host",
"ssh.archflux.net",
"--port",
"5566",
"--no-probe",
"--interactive",
],
)
assert result.exit_code == 0
assert "Session memory is disabled" in result.stdout