Coverage for little_loops / cli / docs.py: 13%

52 statements  

« prev     ^ index     » next       coverage.py v7.12.0, created at 2026-05-11 00:29 -0500

1"""ll-verify-docs and ll-check-links: Documentation verification commands.""" 

2 

3from __future__ import annotations 

4 

5import argparse 

6from pathlib import Path 

7 

8from little_loops.cli.output import configure_output, use_color_enabled 

9from little_loops.logger import Logger 

10 

11 

12def main_verify_docs() -> int: 

13 """Entry point for ll-verify-docs command. 

14 

15 Verify that documented counts (commands, agents, skills) match actual file counts. 

16 

17 Returns: 

18 Exit code (0 = all match, 1 = mismatches found) 

19 """ 

20 from little_loops.doc_counts import ( 

21 fix_counts, 

22 format_result_json, 

23 format_result_markdown, 

24 format_result_text, 

25 verify_documentation, 

26 ) 

27 

28 parser = argparse.ArgumentParser( 

29 prog="ll-verify-docs", 

30 description="Verify documented counts match actual file counts", 

31 formatter_class=argparse.RawDescriptionHelpFormatter, 

32 epilog=""" 

33Examples: 

34 %(prog)s # Check and show results 

35 %(prog)s --json # Output as JSON 

36 %(prog)s --format markdown # Markdown report 

37 %(prog)s --fix # Auto-fix mismatches 

38 

39Exit codes: 

40 0 - All counts match 

41 1 - Mismatches found 

42 2 - Error occurred 

43""", 

44 ) 

45 

46 parser.add_argument( 

47 "-j", 

48 "--json", 

49 action="store_true", 

50 help="Output as JSON", 

51 ) 

52 

53 parser.add_argument( 

54 "-f", 

55 "--format", 

56 choices=["text", "json", "markdown"], 

57 default="text", 

58 help="Output format (default: text)", 

59 ) 

60 

61 parser.add_argument( 

62 "--fix", 

63 action="store_true", 

64 help="Auto-fix count mismatches in documentation files", 

65 ) 

66 

67 parser.add_argument( 

68 "-C", 

69 "--directory", 

70 type=Path, 

71 default=None, 

72 help="Base directory (default: current directory)", 

73 ) 

74 

75 args = parser.parse_args() 

76 

77 configure_output() 

78 logger = Logger(use_color=use_color_enabled()) 

79 

80 # Determine base directory 

81 base_dir = args.directory or Path.cwd() 

82 

83 # Run verification 

84 result = verify_documentation(base_dir) 

85 

86 # Format output 

87 if args.json or args.format == "json": 

88 output = format_result_json(result) 

89 elif args.format == "markdown": 

90 output = format_result_markdown(result) 

91 else: 

92 output = format_result_text(result) 

93 

94 print(output) 

95 

96 # Auto-fix if requested 

97 if args.fix and not result.all_match: 

98 fix_result = fix_counts(base_dir, result) 

99 logger.success( 

100 f"Fixed {fix_result.fixed_count} count(s) in {len(fix_result.files_modified)} file(s)" 

101 ) 

102 

103 # Return exit code based on results 

104 return 0 if result.all_match else 1 

105 

106 

107def main_check_links() -> int: 

108 """Entry point for ll-check-links command. 

109 

110 Check markdown documentation for broken links. 

111 

112 Returns: 

113 Exit code (0 = all links valid, 1 = broken links found, 2 = error) 

114 """ 

115 from little_loops.link_checker import ( 

116 check_markdown_links, 

117 format_result_json, 

118 format_result_markdown, 

119 format_result_text, 

120 load_ignore_patterns, 

121 ) 

122 

123 parser = argparse.ArgumentParser( 

124 prog="ll-check-links", 

125 description="Check markdown documentation for broken links", 

126 formatter_class=argparse.RawDescriptionHelpFormatter, 

127 epilog=""" 

128Examples: 

129 %(prog)s # Check all markdown files 

130 %(prog)s --json # Output as JSON 

131 %(prog)s --format markdown # Markdown report 

132 %(prog)s docs/ # Check specific directory 

133 %(prog)s --ignore 'http://localhost.*' # Ignore pattern 

134 

135Exit codes: 

136 0 - All links valid 

137 1 - Broken links found 

138 2 - Error occurred 

139""", 

140 ) 

141 

142 parser.add_argument( 

143 "-j", 

144 "--json", 

145 action="store_true", 

146 help="Output as JSON", 

147 ) 

148 

149 parser.add_argument( 

150 "-f", 

151 "--format", 

152 choices=["text", "json", "markdown"], 

153 default="text", 

154 help="Output format (default: text)", 

155 ) 

156 

157 parser.add_argument( 

158 "-C", 

159 "--directory", 

160 type=Path, 

161 default=None, 

162 help="Base directory (default: current directory)", 

163 ) 

164 

165 parser.add_argument( 

166 "--ignore", 

167 action="append", 

168 default=[], 

169 help="Ignore URL patterns (can be used multiple times)", 

170 ) 

171 

172 parser.add_argument( 

173 "--timeout", 

174 "-t", 

175 type=int, 

176 default=10, 

177 help="Request timeout in seconds (default: 10)", 

178 ) 

179 

180 parser.add_argument( 

181 "-w", 

182 "--workers", 

183 type=int, 

184 default=10, 

185 help="Maximum concurrent HTTP requests (default: 10)", 

186 ) 

187 

188 parser.add_argument( 

189 "-v", 

190 "--verbose", 

191 action="store_true", 

192 help="Show verbose output", 

193 ) 

194 

195 args = parser.parse_args() 

196 

197 configure_output() 

198 

199 # Determine base directory 

200 base_dir = args.directory or Path.cwd() 

201 

202 # Load ignore patterns from config + CLI args 

203 ignore_patterns = load_ignore_patterns(base_dir) 

204 ignore_patterns.extend(args.ignore) 

205 

206 # Run link check 

207 result = check_markdown_links( 

208 base_dir, ignore_patterns, args.timeout, args.verbose, args.workers 

209 ) 

210 

211 # Format output 

212 if args.json or args.format == "json": 

213 output = format_result_json(result) 

214 elif args.format == "markdown": 

215 output = format_result_markdown(result) 

216 else: 

217 output = format_result_text(result) 

218 

219 print(output) 

220 

221 # Return exit code based on results 

222 if result.has_errors: 

223 return 1 

224 return 0