* Get self-evolution status and morning briefing info
()
| 126 | * Get self-evolution status and morning briefing info |
| 127 | */ |
| 128 | function getEvolutionStatus() { |
| 129 | const statusContent = safeRead(path.join(WORKSPACE_DIR, "memory", "evolution-status.md")); |
| 130 | const heartbeat = safeJson(path.join(WORKSPACE_DIR, "memory", "heartbeat-state.json")); |
| 131 | const skillGaps = safeRead(path.join(WORKSPACE_DIR, "memory", "skill-gaps.md")); |
| 132 | |
| 133 | // Parse improvement items from evolution-status.md |
| 134 | const improvements: Array<{ title: string; priority: string }> = []; |
| 135 | const recommendations: Array<{ name: string; type: string }> = []; |
| 136 | |
| 137 | if (statusContent) { |
| 138 | const lines = statusContent.split("\n"); |
| 139 | let inImprovements = false; |
| 140 | let inRecommendations = false; |
| 141 | |
| 142 | for (const line of lines) { |
| 143 | // These keywords must match the section headers in your Markdown files |
| 144 | if (line.includes("Improvements")) { inImprovements = true; inRecommendations = false; continue; } |
| 145 | if (line.includes("Recommended Assets")) { inRecommendations = true; inImprovements = false; continue; } |
| 146 | if (line.includes("Installed Records") || line.includes("Last Updated")) { inImprovements = false; inRecommendations = false; continue; } |
| 147 | |
| 148 | if (inImprovements) { |
| 149 | const match = line.match(/^\d+\.\s+\*\*(.+?)\*\*\s*—\s*(.+)/); |
| 150 | if (match) { |
| 151 | // Priority keywords must match those used in your Markdown files |
| 152 | const priorityMatch = line.match(/Priority:\s*(High|Medium|Low)/i); |
| 153 | improvements.push({ title: match[1], priority: priorityMatch ? priorityMatch[1] : "Medium" }); |
| 154 | } |
| 155 | } |
| 156 | |
| 157 | if (inRecommendations) { |
| 158 | const match = line.match(/^\d+\.\s+\*\*(.+?)\*\*\s+\((\w+)\)/); |
| 159 | if (match) { |
| 160 | recommendations.push({ name: match[1], type: match[2] }); |
| 161 | } |
| 162 | } |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | // Count today's skill gaps |
| 167 | const todayStr = new Date().toISOString().split("T")[0]; |
| 168 | const todayGaps = skillGaps.split("\n").filter((l) => l.includes(`[${todayStr}]`)).length; |
| 169 | |
| 170 | // Get installed skills |
| 171 | const skillsDir = path.join(WORKSPACE_DIR, "skills"); |
| 172 | let skills: string[] = []; |
| 173 | try { |
| 174 | skills = fs.readdirSync(skillsDir).filter((d) => { |
| 175 | try { |
| 176 | return fs.statSync(path.join(skillsDir, d)).isDirectory(); |
| 177 | } catch { |
| 178 | return false; |
| 179 | } |
| 180 | }); |
| 181 | } catch { |
| 182 | // no skills dir |
| 183 | } |
| 184 | |
| 185 | return { |