Coverage for src/lilbee/cli/commands/meta.py: 100%

79 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-11-06 08:17 +0000

1"""Version, status, reset, and init commands.""" 

2 

3from __future__ import annotations 

4 

5from pathlib import Path 

6 

7import typer 

8from rich.text import Text 

9 

10from lilbee.app.reset import perform_reset 

11from lilbee.app.services import reset_store 

12from lilbee.app.status import gather_status 

13from lilbee.app.version import get_version 

14from lilbee.cli import theme 

15from lilbee.cli.app import ( 

16 apply_overrides, 

17 console, 

18 data_dir_option, 

19 global_option, 

20) 

21from lilbee.cli.commands.analyze import print_tip_if_shown 

22from lilbee.cli.helpers import json_output, print_prefixed, print_source_listing, render_status 

23from lilbee.core.config import cfg 

24from lilbee.core.system import LOCAL_ROOT_DIRNAME 

25from lilbee.data.ingest.ignore import IGNORE_FILENAME, IGNORE_TEMPLATE 

26from lilbee.runtime.lock import ResetRefusedError 

27 

28_yes_option = typer.Option(False, "--yes", "-y", help="Skip confirmation prompt.") 

29_list_sources_option = typer.Option( 

30 False, 

31 "--list-sources", 

32 help="Print every indexed document, one per line (one JSON object per line with --json).", 

33) 

34 

35 

36def version() -> None: 

37 """Show the lilbee version.""" 

38 ver = get_version() 

39 if cfg.json_mode: 

40 json_output({"command": "version", "version": ver}) 

41 return 

42 console.print(f"lilbee {ver}") 

43 

44 

45def status( 

46 data_dir: Path | None = data_dir_option, 

47 use_global: bool = global_option, 

48 list_sources: bool = _list_sources_option, 

49) -> None: 

50 """Show counts, paths, and the newest indexed documents.""" 

51 apply_overrides(data_dir=data_dir, use_global=use_global) 

52 # Status only reads the store; don't warm the inference fleet for a read. 

53 cfg.worker_pool_eager_start = False 

54 if list_sources: 

55 print_source_listing() 

56 return 

57 if cfg.json_mode: 

58 json_output(gather_status().model_dump(exclude_none=True)) 

59 return 

60 render_status(console) 

61 

62 

63def reset( 

64 data_dir: Path | None = data_dir_option, 

65 use_global: bool = global_option, 

66 yes: bool = _yes_option, 

67) -> None: 

68 """Delete all documents and data (full factory reset).""" 

69 apply_overrides(data_dir=data_dir, use_global=use_global) 

70 if not yes: 

71 if cfg.json_mode: 

72 json_output({"error": "Use --yes to confirm reset in JSON mode"}) 

73 raise SystemExit(1) 

74 console.print( 

75 Text.assemble( 

76 ("This will delete ALL documents and data.\n", theme.ERROR_BOLD), 

77 f" Documents: {cfg.documents_dir}\n", 

78 f" Data: {cfg.data_dir}", 

79 ), 

80 soft_wrap=True, 

81 ) 

82 confirmed = typer.confirm("Are you sure?", default=False) 

83 if not confirmed: 

84 console.print("Aborted.") 

85 raise SystemExit(0) 

86 

87 try: 

88 result = perform_reset() 

89 except ResetRefusedError as exc: 

90 if cfg.json_mode: 

91 json_output({"error": str(exc)}) 

92 else: 

93 print_prefixed(console, "Error: ", exc, style=theme.ERROR) 

94 raise SystemExit(1) from None 

95 # Reopen LanceDB against the empty data dir; keep providers loaded. 

96 reset_store() 

97 

98 if cfg.json_mode: 

99 json_output(result.model_dump()) 

100 return 

101 

102 console.print( 

103 f"Reset complete: {result.deleted_docs} document(s), " 

104 f"{result.deleted_data} data item(s) deleted.", 

105 ) 

106 if result.skipped: 

107 console.print( 

108 f"{len(result.skipped)} item(s) could not be deleted (locked or permission denied).", 

109 style=theme.WARNING, 

110 ) 

111 

112 

113def init() -> None: 

114 """Initialize a local .lilbee/ knowledge base in the current directory.""" 

115 root = Path.cwd() / LOCAL_ROOT_DIRNAME 

116 if root.is_dir(): 

117 if cfg.json_mode: 

118 json_output({"command": "init", "path": str(root), "created": False}) 

119 return 

120 console.print(f"Already initialized: {root}", soft_wrap=True) 

121 print_tip_if_shown(root) 

122 return 

123 

124 docs = root / "documents" 

125 data = root / "data" 

126 docs.mkdir(parents=True) 

127 data.mkdir(parents=True) 

128 (root / ".gitignore").write_text("data/\n", encoding="utf-8") 

129 (root / IGNORE_FILENAME).write_text(IGNORE_TEMPLATE, encoding="utf-8") 

130 

131 if cfg.json_mode: 

132 json_output({"command": "init", "path": str(root), "created": True}) 

133 return 

134 console.print(f"Initialized local knowledge base at {root}", soft_wrap=True) 

135 print_tip_if_shown(root)