1#!/usr/bin/env python3

2"""Formatting and output utilities for session management.

3

4 This module provides text formatting and display functionality following

5 crackerjack architecture patterns with single responsibility principle.

6"""

7

8 from __future__ import annotations

9

10 from typing import Any

11

12

13 def _format_statistics_header(user_id: str) -> list[str]:

14 """Format the header section for interruption statistics."""

15 return [

16 f"📊 **Interruption Statistics for {user_id}**",

17 "",

18 ]

19

20

21 def _format_session_statistics(sessions: dict[str, Any]) -> list[str]:

22 """Format session-related statistics."""

23 if not sessions:

24 return ["📝 No session data available"]

25

26 return [

27 "**Session Activity:**",

28 f"• Total sessions: {sessions.get('total', 0)}",

29 f"• Average duration: {sessions.get('avg_duration_minutes', 0):.1f} minutes",

30 f"• Longest session: {sessions.get('max_duration_minutes', 0):.1f} minutes",

31 "",

32 ]

33

34

35 def _format_interruption_type_details(by_type: list[Any]) -> list[str]:

36 """Format interruption type breakdown."""

37 if not by_type:

38 return []

39

40 lines = ["**Interruption Types:**"]

41 for item in by_type[:5]: # Show top 5

42 lines.append(f"• {item['type']}: {item['count']} occurrences")

43

44 lines.append("")

45 return lines

46

47

48 def _format_interruption_statistics(interruptions: dict[str, Any]) -> list[str]:

49 """Format interruption-related statistics."""

50 if not interruptions:

51 return ["🚫 No interruption data available"]

52

53 lines = [

54 "**Interruption Patterns:**",

55 f"• Total interruptions: {interruptions.get('total', 0)}",

56 f"• Average per session: {interruptions.get('avg_per_session', 0):.1f}",

57 f"• Most active hour: {interruptions.get('peak_hour', 'Unknown')}",

58 "",

59 ]

60

61 # Add type breakdown if available

62 if "by_type" in interruptions:

63 lines.extend(_format_interruption_type_details(interruptions["by_type"]))

64

65 return lines

66

67

68 def _format_snapshot_statistics(snapshots: dict[str, Any]) -> list[str]:

69 """Format snapshot-related statistics."""

70 if not snapshots:

71 return ["💾 No snapshot data available"]

72

73 return [

74 "**Context Snapshots:**",

75 f"• Total snapshots: {snapshots.get('total', 0)}",

76 f"• Successful restores: {snapshots.get('successful_restores', 0)}",

77 f"• Average snapshot size: {snapshots.get('avg_size_kb', 0):.1f} KB",

78 "",

79 ]

80

81

82 def _calculate_efficiency_rates(

83 sessions: dict[str, Any],

84 interruptions: dict[str, Any],

85 snapshots: dict[str, Any],

86) -> dict[str, float]:

87 """Calculate efficiency metrics from statistics."""

88 efficiency = {

89 "interruption_rate": 0.0,

90 "recovery_rate": 0.0,

91 "productivity_score": 0.0,

92 }

93

94 if sessions.get("total", 0) > 0:

95 efficiency["interruption_rate"] = (

96 interruptions.get("total", 0) / sessions["total"]

97 )

98

99 if snapshots.get("total", 0) > 0:

100 efficiency["recovery_rate"] = (

101 snapshots.get("successful_restores", 0) / snapshots["total"]

102 )

103

104 # Simple productivity score (inverse of interruption rate, scaled)

105 efficiency["productivity_score"] = max(

106 0,

107 100 - (efficiency["interruption_rate"] * 20),

108 )

109

110 return efficiency

111

112

113 def _format_efficiency_metrics(

114 sessions: dict[str, Any],

115 interruptions: dict[str, Any],

116 snapshots: dict[str, Any],

117) -> list[str]:

118 """Format efficiency and productivity metrics."""

119 efficiency = _calculate_efficiency_rates(sessions, interruptions, snapshots)

120

121 return [

122 "**Efficiency Metrics:**",

123 f"• Interruption rate: {efficiency['interruption_rate']:.2f} per session",

124 f"• Context recovery rate: {efficiency['recovery_rate']:.1%}",

125 f"• Productivity score: {efficiency['productivity_score']:.1f}/100",

126 "",

127 ]

128

129

130 def _has_statistics_data(

131 sessions: dict[str, Any],

132 interruptions: dict[str, Any],

133 snapshots: dict[str, Any],

134) -> bool:

135 """Check if any meaningful statistics data exists."""

136 return bool(

137 sessions.get("total", 0) > 0

138 or interruptions.get("total", 0) > 0

139 or snapshots.get("total", 0) > 0,

140 )

141

142

143 def _format_no_data_message(user_id: str) -> list[str]:

144 """Format message when no statistics data is available."""

145 return [

146 f"📊 **No Statistics Available for {user_id}**",

147 "",

148 "No interruption monitoring data found. To start collecting statistics:",

149 "• Use the start_interruption_monitoring tool",

150 "• Work on development tasks with file monitoring enabled",

151 "• Create session contexts to track productivity patterns",

152 "",

153 "Statistics will be available after some monitored activity.",

154 ]

155

156

157 def _build_search_header(

158 query: str,

159 total_found: int,

160 chunk_info: dict[str, Any] | None = None,

161) -> list[str]:

162 """Build formatted header for search results."""

163 header = [f"🔍 **Search Results for: '{query}'**", ""]

164

165 if chunk_info:

166 current = chunk_info.get("current_chunk", 1)

167 total = chunk_info.get("total_chunks", 1)

168 header.extend(

169 [

170 f"📊 Found {total_found} results (Page {current}/{total})",

171 "",

172 ],

173 )

174 else:

175 header.extend(

176 [

177 f"📊 Found {total_found} results",

178 "",

179 ],

180 )

181

182 return header

183

184

185 def _format_search_results(results: list[Any]) -> list[str]:

186 """Format search results for display."""

187 if not results: 187 ↛ 188 line 187 didn't jump to line 188 because the condition on line 187 was never true

188 return ["No results found"]

189

190 formatted = []

191

192 for i, result in enumerate(results, 1):

193 content = result.get("content", "").strip()

194 project = result.get("project", "Unknown")

195 timestamp = result.get("timestamp", "")

196

197 # Truncate content for display

198 if len(content) > 300:

199 content = content[:297] + "..."

200

201 formatted.extend(

202 [

203 f"**{i}. [{project}]** {timestamp}",

204 f" {content}",

205 "",

206 ],

207 )

208

209 return formatted

210

211

212 def _format_monitoring_status(quality_data: dict[str, Any]) -> list[str]:

213 """Format current monitoring status information."""

214 lines = [

215 "📊 **Current Monitoring Status**",

216 "",

217 ]

218

219 if quality_data.get("monitoring_active"):

220 lines.extend(

221 [

222 "✅ Quality monitoring is active",

223 f"• Last check: {quality_data.get('last_check', 'Unknown')}",

224 f"• Checks performed: {quality_data.get('total_checks', 0)}",

225 ],

226 )

227 else:

228 lines.extend(

229 [

230 "⏸️ Quality monitoring is inactive",

231 "• Use quality_monitor tool to start monitoring",

232 ],

233 )

234

235 lines.append("")

236 return lines

237

238

239 def _format_quality_trend(quality_data: dict[str, Any]) -> list[str]:

240 """Format quality trend information."""

241 trend = quality_data.get("trend", {})

242 if not trend:

243 return ["📈 No trend data available"]

244

245 return [

246 "📈 **Quality Trend Analysis**",

247 "",

248 f"• Current quality score: {trend.get('current_score', 0)}/100",

249 f"• Trend direction: {trend.get('direction', 'Unknown')}",

250 f"• Change from last check: {trend.get('change', 0):+.1f} points",

251 "",

252 ]

253

254

255 def _format_quality_alerts(quality_data: dict[str, Any]) -> list[str]:

256 """Format quality alerts and warnings."""

257 alerts = quality_data.get("alerts", [])

258 if not alerts:

259 return ["✅ No quality alerts"]

260

261 lines = [

262 "🚨 **Quality Alerts**",

263 "",

264 ]

265

266 for alert in alerts:

267 severity = alert.get("severity", "info")

268 message = alert.get("message", "")

269 icon = {"high": "🔴", "medium": "🟡", "low": "🔵"}.get(severity, "ℹ️")

270 lines.append(f"{icon} {message}")

271

272 lines.append("")

273 return lines

274

275

276 def _format_proactive_recommendations(quality_data: dict[str, Any]) -> list[str]:

277 """Format proactive quality improvement recommendations."""

278 recommendations = quality_data.get("recommendations", [])

279 if not recommendations:

280 return ["💡 No recommendations at this time"]

281

282 lines = [

283 "💡 **Proactive Recommendations**",

284 "",

285 ]

286

287 for i, rec in enumerate(recommendations, 1):

288 lines.append(f"{i}. {rec}")

289

290 lines.append("")

291 return lines

292

293

294 def _format_monitor_usage_guidance() -> list[str]:

295 """Format usage guidance for quality monitoring."""

296 return [

297 "📖 **Usage Guidance**",

298 "",

299 "• Run quality_monitor periodically to track project health",

300 "• Monitor alerts for early warning of quality issues",

301 "• Follow recommendations to maintain code quality",

302 "• Use with Crackerjack integration for best results",

303 "",

304 "Quality monitoring helps maintain consistent development standards.",

305 ]