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

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

2

3 from __future__ import annotations

4

5 import argparse

6 from pathlib import Path

7

8

9 def main_verify_docs() -> int:

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

11

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

13

14 Returns:

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

16 """

17 from little_loops.doc_counts import (

18 fix_counts,

19 format_result_json,

20 format_result_markdown,

21 format_result_text,

22 verify_documentation,

23 )

24

25 parser = argparse.ArgumentParser(

26 prog="ll-verify-docs",

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

28 formatter_class=argparse.RawDescriptionHelpFormatter,

29 epilog="""

30 Examples:

31 %(prog)s # Check and show results

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

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

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

35

36 Exit codes:

37 0 - All counts match

38 1 - Mismatches found

39 2 - Error occurred

40""",

41 )

42

43 parser.add_argument(

44 "-j",

45 "--json",

46 action="store_true",

47 help="Output as JSON",

48 )

49

50 parser.add_argument(

51 "-f",

52 "--format",

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

54 default="text",

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

56 )

57

58 parser.add_argument(

59 "--fix",

60 action="store_true",

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

62 )

63

64 parser.add_argument(

65 "-C",

66 "--directory",

67 type=Path,

68 default=None,

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

70 )

71

72 args = parser.parse_args()

73

74 # Determine base directory

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

76

77 # Run verification

78 result = verify_documentation(base_dir)

79

80 # Format output

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

82 output = format_result_json(result)

83 elif args.format == "markdown":

84 output = format_result_markdown(result)

85 else:

86 output = format_result_text(result)

87

88 print(output)

89

90 # Auto-fix if requested

91 if args.fix and not result.all_match:

92 fix_result = fix_counts(base_dir, result)

93 print(

94 f"\nFixed {fix_result.fixed_count} count(s) in {len(fix_result.files_modified)} file(s)"

95 )

96

97 # Return exit code based on results

98 return 0 if result.all_match else 1

99

100

101 def main_check_links() -> int:

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

103

104 Check markdown documentation for broken links.

105

106 Returns:

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

108 """

109 from little_loops.link_checker import (

110 check_markdown_links,

111 format_result_json,

112 format_result_markdown,

113 format_result_text,

114 load_ignore_patterns,

115 )

116

117 parser = argparse.ArgumentParser(

118 prog="ll-check-links",

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

120 formatter_class=argparse.RawDescriptionHelpFormatter,

121 epilog="""

122 Examples:

123 %(prog)s # Check all markdown files

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

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

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

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

128

129 Exit codes:

130 0 - All links valid

131 1 - Broken links found

132 2 - Error occurred

133""",

134 )

135

136 parser.add_argument(

137 "-j",

138 "--json",

139 action="store_true",

140 help="Output as JSON",

141 )

142

143 parser.add_argument(

144 "-f",

145 "--format",

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

147 default="text",

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

149 )

150

151 parser.add_argument(

152 "-C",

153 "--directory",

154 type=Path,

155 default=None,

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

157 )

158

159 parser.add_argument(

160 "--ignore",

161 action="append",

162 default=[],

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

164 )

165

166 parser.add_argument(

167 "--timeout",

168 type=int,

169 default=10,

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

171 )

172

173 parser.add_argument(

174 "-w",

175 "--workers",

176 type=int,

177 default=10,

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

179 )

180

181 parser.add_argument(

182 "-v",

183 "--verbose",

184 action="store_true",

185 help="Show verbose output",

186 )

187

188 args = parser.parse_args()

189

190 # Determine base directory

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

192

193 # Load ignore patterns from config + CLI args

194 ignore_patterns = load_ignore_patterns(base_dir)

195 ignore_patterns.extend(args.ignore)

196

197 # Run link check

198 result = check_markdown_links(

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

200 )

201

202 # Format output

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

204 output = format_result_json(result)

205 elif args.format == "markdown":

206 output = format_result_markdown(result)

207 else:

208 output = format_result_text(result)

209

210 print(output)

211

212 # Return exit code based on results

213 if result.has_errors:

214 return 1

215 return 0