()
| 52 | } |
| 53 | |
| 54 | function main() { |
| 55 | health.increment('pre-compact', 'count'); |
| 56 | |
| 57 | const config = health.readConfig(); |
| 58 | const preCompactConfig = config.preCompact || {}; |
| 59 | const handoffMode = preCompactConfig.handoffMode || 'auto'; |
| 60 | |
| 61 | const state = { |
| 62 | savedAt: new Date().toISOString(), |
| 63 | activeCampaign: null, |
| 64 | activeFleetSession: null, |
| 65 | recentContext: null, |
| 66 | pendingResearch: [], |
| 67 | handoffMode, |
| 68 | }; |
| 69 | |
| 70 | // Find active campaign |
| 71 | const campaignsDir = path.join(PROJECT_ROOT, '.planning', 'campaigns'); |
| 72 | if (fs.existsSync(campaignsDir)) { |
| 73 | try { |
| 74 | const files = fs.readdirSync(campaignsDir).filter(f => f.endsWith('.md')); |
| 75 | for (const file of files) { |
| 76 | const content = fs.readFileSync(path.join(campaignsDir, file), 'utf8'); |
| 77 | if (/^Status:\s*active/mi.test(content)) { |
| 78 | state.activeCampaign = file.replace('.md', ''); |
| 79 | const ctxMatch = content.match(/## Active Context\s*\n([\s\S]*?)(?=\n## |\n---|$)/); |
| 80 | if (ctxMatch) state.recentContext = ctxMatch[1].trim().slice(0, 500); |
| 81 | const nextMatch = content.match(/## Continuation State\s*\n([\s\S]*?)(?=\n## |\n---|$)/); |
| 82 | if (nextMatch) state.continuationState = nextMatch[1].trim().slice(0, 500); |
| 83 | break; |
| 84 | } |
| 85 | } |
| 86 | } catch { /* non-critical */ } |
| 87 | } |
| 88 | |
| 89 | // Find active fleet session |
| 90 | const fleetDir = path.join(PROJECT_ROOT, '.planning', 'fleet'); |
| 91 | if (fs.existsSync(fleetDir)) { |
| 92 | try { |
| 93 | const files = fs.readdirSync(fleetDir).filter(f => f.startsWith('session-') && f.endsWith('.md')); |
| 94 | for (const file of files) { |
| 95 | const content = fs.readFileSync(path.join(fleetDir, file), 'utf8'); |
| 96 | if (/status:\s*(active|needs-continue)/mi.test(content)) { |
| 97 | state.activeFleetSession = file.replace('session-', '').replace('.md', ''); |
| 98 | break; |
| 99 | } |
| 100 | } |
| 101 | } catch { /* non-critical */ } |
| 102 | } |
| 103 | |
| 104 | // Detect recent research artifacts (modified in last 2 hours) |
| 105 | const researchDir = path.join(PROJECT_ROOT, '.planning', 'research'); |
| 106 | if (fs.existsSync(researchDir)) { |
| 107 | try { |
| 108 | const twoHoursAgo = Date.now() - 2 * 60 * 60 * 1000; |
| 109 | const scanDir = (dir) => { |
| 110 | const entries = fs.readdirSync(dir, { withFileTypes: true }); |
| 111 | for (const entry of entries) { |
no test coverage detected