Initial commit with translated description
This commit is contained in:
121
scripts/analyze_by_skill.js
Normal file
121
scripts/analyze_by_skill.js
Normal file
@@ -0,0 +1,121 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const REPO_ROOT = path.resolve(__dirname, '..');
|
||||
const LOG_FILE = path.join(REPO_ROOT, 'evolution_history_full.md');
|
||||
const OUT_FILE = path.join(REPO_ROOT, 'evolution_detailed_report.md');
|
||||
|
||||
function analyzeEvolution() {
|
||||
if (!fs.existsSync(LOG_FILE)) {
|
||||
console.error("Source file missing.");
|
||||
return;
|
||||
}
|
||||
|
||||
const content = fs.readFileSync(LOG_FILE, 'utf8');
|
||||
// Split by divider
|
||||
const entries = content.split('---').map(e => e.trim()).filter(e => e.length > 0);
|
||||
|
||||
const skillUpdates = {}; // Map<SkillName, Array<Changes>>
|
||||
const generalUpdates = []; // Array<Changes>
|
||||
|
||||
// Regex to detect skills/paths
|
||||
// e.g. `skills/feishu-card/send.js` or **Target**: `skills/git-sync`
|
||||
const skillRegex = /skills\/([a-zA-Z0-9\-_]+)/;
|
||||
const actionRegex = /Action:\s*([\s\S]*?)(?=\n\n|\n[A-Z]|$)/i; // Capture Action text
|
||||
const statusRegex = /Status:\s*\[?([A-Z\s_]+)\]?/i;
|
||||
|
||||
entries.forEach(entry => {
|
||||
// Extract basic info
|
||||
const statusMatch = entry.match(statusRegex);
|
||||
const status = statusMatch ? statusMatch[1].trim().toUpperCase() : 'UNKNOWN';
|
||||
|
||||
// Skip routine checks if we want a *detailed evolution* report (focus on changes)
|
||||
// But user asked for "what happened", so routine scans might be boring unless they found something.
|
||||
// Let's filter out "STABILITY" or "RUNNING" unless there is a clear "Mutated" or "Fixed" keyword.
|
||||
const isInteresting =
|
||||
entry.includes('Fixed') ||
|
||||
entry.includes('Hardened') ||
|
||||
entry.includes('Optimized') ||
|
||||
entry.includes('Patched') ||
|
||||
entry.includes('Created') ||
|
||||
entry.includes('Added') ||
|
||||
status === 'SUCCESS' ||
|
||||
status === 'COMPLETED';
|
||||
|
||||
if (!isInteresting) return;
|
||||
|
||||
// Find associated skill
|
||||
const skillMatch = entry.match(skillRegex);
|
||||
let skillName = 'General / System';
|
||||
if (skillMatch) {
|
||||
skillName = skillMatch[1];
|
||||
} else {
|
||||
// Try heuristics
|
||||
if (entry.toLowerCase().includes('feishu card')) skillName = 'feishu-card';
|
||||
else if (entry.toLowerCase().includes('git sync')) skillName = 'git-sync';
|
||||
else if (entry.toLowerCase().includes('logger')) skillName = 'interaction-logger';
|
||||
else if (entry.toLowerCase().includes('evolve')) skillName = 'capability-evolver';
|
||||
}
|
||||
|
||||
// Extract description
|
||||
let description = "";
|
||||
const actionMatch = entry.match(actionRegex);
|
||||
if (actionMatch) {
|
||||
description = actionMatch[1].trim();
|
||||
} else {
|
||||
// Fallback: take lines that look like bullet points or text after header
|
||||
const lines = entry.split('\n');
|
||||
description = lines.filter(l => l.match(/^[•\-\*]|\w/)).slice(1).join('\n').trim();
|
||||
}
|
||||
|
||||
// Clean up description (remove duplicate "Action:" prefix if captured)
|
||||
description = description.replace(/^Action:\s*/i, '');
|
||||
|
||||
if (!skillUpdates[skillName]) skillUpdates[skillName] = [];
|
||||
|
||||
// Dedup descriptions slightly (simple check)
|
||||
const isDuplicate = skillUpdates[skillName].some(u => u.desc.includes(description.substring(0, 20)));
|
||||
if (!isDuplicate) {
|
||||
// Extract Date if possible
|
||||
const dateMatch = entry.match(/\((\d{4}\/\d{1,2}\/\d{1,2}.*?)\)/);
|
||||
const date = dateMatch ? dateMatch[1] : 'Unknown';
|
||||
|
||||
skillUpdates[skillName].push({
|
||||
date,
|
||||
status,
|
||||
desc: description
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Generate Markdown
|
||||
let md = "# Detailed Evolution Report (By Skill)\n\n> Comprehensive breakdown of system changes.\n\n";
|
||||
|
||||
// Sort skills alphabetically
|
||||
const sortedSkills = Object.keys(skillUpdates).sort();
|
||||
|
||||
sortedSkills.forEach(skill => {
|
||||
md += `## ${skill}\n`;
|
||||
const updates = skillUpdates[skill];
|
||||
|
||||
updates.forEach(u => {
|
||||
// Icon based on content
|
||||
let icon = '*';
|
||||
const lowerDesc = u.desc.toLowerCase();
|
||||
if (lowerDesc.includes('optimiz')) icon = '[optimize]';
|
||||
if (lowerDesc.includes('secur') || lowerDesc.includes('harden') || lowerDesc.includes('permission')) icon = '[security]';
|
||||
if (lowerDesc.includes('fix') || lowerDesc.includes('patch')) icon = '[repair]';
|
||||
if (lowerDesc.includes('creat') || lowerDesc.includes('add')) icon = '[add]';
|
||||
|
||||
md += `### ${icon} ${u.date}\n`;
|
||||
md += `${u.desc}\n\n`;
|
||||
});
|
||||
md += `---\n`;
|
||||
});
|
||||
|
||||
fs.writeFileSync(OUT_FILE, md);
|
||||
console.log(`Generated report for ${sortedSkills.length} skills.`);
|
||||
}
|
||||
|
||||
analyzeEvolution();
|
||||
|
||||
Reference in New Issue
Block a user