Coverage for src / lilbee / server / routes / setup.py: 100%

30 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-04-29 19:16 +0000

1"""Setup routes: status and bootstrap for optional runtime components. 

2 

3Currently exposes Playwright Chromium bootstrap (needed for /crawl). The 

4bb-wq8g contract mirrors what the TUI does in ``TaskBarController.ensure_chromium`` 

5so the Obsidian plugin's Task Center can render a matching ``setup`` pill. 

6 

7Endpoints: 

8 GET /setup/crawler/status → { installed, component, browsers_path } 

9 POST /setup/crawler → text/event-stream of setup_start → 

10 setup_progress → setup_done → done 

11""" 

12 

13from __future__ import annotations 

14 

15import asyncio 

16from collections.abc import AsyncGenerator 

17from typing import Any 

18 

19from litestar import get, post 

20from litestar.response import Stream 

21 

22from lilbee.crawler import ( 

23 bootstrap_chromium, 

24 chromium_installed, 

25 crawler_browsers_path, 

26) 

27from lilbee.server.handlers import SseStream, sse_done, sse_error 

28 

29 

30@get("/setup/crawler/status") 

31async def setup_crawler_status_route() -> dict[str, Any]: 

32 """Return whether the Chromium browser is installed.""" 

33 return { 

34 "installed": chromium_installed(), 

35 "component": "chromium", 

36 "browsers_path": str(crawler_browsers_path()), 

37 } 

38 

39 

40async def _bootstrap_crawler_stream() -> AsyncGenerator[str, None]: 

41 sse = SseStream() 

42 

43 async def _run() -> None: 

44 try: 

45 await bootstrap_chromium(on_progress=sse.callback) 

46 finally: 

47 sse.queue.put_nowait(None) 

48 

49 task = asyncio.create_task(_run()) 

50 async for event in sse.drain(task, "Crawler setup stream"): 

51 yield event 

52 if task.done() and not task.cancelled(): 

53 exc = task.exception() 

54 if exc is not None: 

55 yield sse_error(str(exc)) 

56 return 

57 yield sse_done({}) 

58 

59 

60@post("/setup/crawler") 

61async def setup_crawler_route() -> Stream: 

62 """Stream the Chromium bootstrap subprocess as SSE events.""" 

63 return Stream(_bootstrap_crawler_stream(), media_type="text/event-stream") 

64 

65 

66__all__ = [ 

67 "setup_crawler_route", 

68 "setup_crawler_status_route", 

69]