import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, copyFileSync, renameSync } from "fs"; import { basename, dirname } from "path"; import { toRepoRelativePath, TICKET_SUBDIR, TICKET_LIST_FILENAME, parseFrontMatter, findFileRecursively, detectConsumerTicketDir, makePath , CliOpts } from "./cli-utils.js"; import { readTicketIndexJson, syncActiveTicketId, writeTicketIndexJson } from "./cli-ticket-index.js"; import { collectTicketMarkdownFiles, rebuildTicketIndexFromTopicFilesIfNeeded } from "./cli-ticket-parser.js"; import { splitTicketDocMetaSection } from "./cli-ticket-docmeta.js"; import { writeTicketDocument } from "./cli-ticket-document.js"; // ─── Summary Extraction ───────────────────────────────────────────────────── /** * Extracts a concise summary from ticket body content for legacy tickets. * Strategy: combine title + scope/background + top tasks into 1-2 lines. * Handles 3 legacy formats: * - Old format: 🎯 Scope Bounds, 📁 Files to Modify * - Mid format: ## Background, ## Analysis, ## Tasks * - New format: ## Target Module, ## APC (already has summary usually) */ export function extractSummary(meta, content) { const title = meta.title || ""; const lines = content.split("\n"); // Collect section contents by known header patterns const sections: Record = {}; let currentSection = null; for (const line of lines) { const trimmed = line.trim(); // Match ## headers (with or without emoji prefix) const headerMatch = trimmed.match(/^##\s+(?:[\u{1F3AF}\u{1F4C1}\u{1F3D7}\u{1F6D1}\u{1F504}\u{2705}\s]*)?(.+)$/u); if (headerMatch) { currentSection = headerMatch[1].trim().toLowerCase(); sections[currentSection] = []; continue; } // Match # title if (trimmed.startsWith("# ") && !currentSection) { continue; // skip title line } if (currentSection && trimmed && !trimmed.startsWith(">") && !trimmed.startsWith("