* Formats safe outputs preview for display in logs * @param {string} safeOutputsContent - The raw JSONL content from safe outputs file * @param {Object} options - Configuration options * @param {boolean} [options.isPlainText=false] - Whether to format for plain text (core.info) or markdown (step
(safeOutputsContent, options = {})
| 1212 | * @returns {string} Formatted safe outputs preview |
| 1213 | */ |
| 1214 | function formatSafeOutputsPreview(safeOutputsContent, options = {}) { |
| 1215 | const { isPlainText = false, maxEntries = 5 } = options; |
| 1216 | |
| 1217 | if (!safeOutputsContent || safeOutputsContent.trim().length === 0) { |
| 1218 | return ""; |
| 1219 | } |
| 1220 | |
| 1221 | const lines = safeOutputsContent.trim().split("\n"); |
| 1222 | const entries = []; |
| 1223 | |
| 1224 | // Parse JSONL entries |
| 1225 | for (const line of lines) { |
| 1226 | if (!line.trim()) continue; |
| 1227 | try { |
| 1228 | const entry = JSON.parse(line); |
| 1229 | entries.push(entry); |
| 1230 | } catch (e) { |
| 1231 | // Skip invalid JSON lines |
| 1232 | continue; |
| 1233 | } |
| 1234 | } |
| 1235 | |
| 1236 | if (entries.length === 0) { |
| 1237 | return ""; |
| 1238 | } |
| 1239 | |
| 1240 | // Build preview |
| 1241 | const preview = []; |
| 1242 | const entriesToShow = entries.slice(0, maxEntries); |
| 1243 | const hasMore = entries.length > maxEntries; |
| 1244 | |
| 1245 | if (isPlainText) { |
| 1246 | // Plain text format for core.info |
| 1247 | preview.push(""); |
| 1248 | preview.push("Safe Outputs Preview:"); |
| 1249 | preview.push(` Total: ${entries.length} ${entries.length === 1 ? "entry" : "entries"}`); |
| 1250 | |
| 1251 | for (let i = 0; i < entriesToShow.length; i++) { |
| 1252 | const entry = entriesToShow[i]; |
| 1253 | preview.push(""); |
| 1254 | preview.push(` [${i + 1}] ${entry.type || "unknown"}`); |
| 1255 | if (entry.title) { |
| 1256 | const titleStr = typeof entry.title === "string" ? entry.title : String(entry.title); |
| 1257 | preview.push(` Title: ${truncateString(titleStr, 60)}`); |
| 1258 | } |
| 1259 | if (entry.body) { |
| 1260 | const bodyStr = typeof entry.body === "string" ? entry.body : String(entry.body); |
| 1261 | const bodyPreview = truncateString(bodyStr.replace(/\n/g, " "), 80); |
| 1262 | preview.push(` Body: ${bodyPreview}`); |
| 1263 | } |
| 1264 | } |
| 1265 | |
| 1266 | if (hasMore) { |
| 1267 | preview.push(""); |
| 1268 | preview.push(` ... and ${entries.length - maxEntries} more ${entries.length - maxEntries === 1 ? "entry" : "entries"}`); |
| 1269 | } |
| 1270 | } else { |
| 1271 | // Markdown format for step summary |
no test coverage detected