virtue-cli
Version:
Personal character development CLI tool for tracking virtues and philosophical alignment
216 lines (208 loc) • 9.86 kB
JavaScript
import { intro, outro, log, select, spinner } from '@clack/prompts';
import { ClaudeService } from '../services/ClaudeService.js';
import { calculateAlignment, calculateCoherence } from '../utils/helpers.js';
import picocolors from 'picocolors';
export class AIInsights {
db;
profile;
claudeService;
constructor(db, profile) {
this.db = db;
this.profile = profile;
this.claudeService = new ClaudeService();
}
async generate() {
intro(picocolors.cyan('🧠 AI Insights'));
if (!this.claudeService.isConfigured()) {
log.error('Claude AI not available. Run via Claude Code to enable insights.');
outro(picocolors.yellow('💡 Tip: Use `virtue analytics` for detailed analysis without AI'));
return;
}
try {
const insightType = await select({
message: 'What type of insights would you like?',
options: [
{ value: 'personal', label: '🎯 Personal Growth Analysis', hint: 'Tailored insights for your journey' },
{ value: 'patterns', label: '📊 Pattern Recognition', hint: 'Hidden patterns in your data' },
{ value: 'interventions', label: '💪 Actionable Interventions', hint: 'Specific steps to improve' },
{ value: 'philosophical', label: '🏛️ Philosophical Guidance', hint: 'Deeper wisdom and reflection' }
]
});
const s = spinner();
s.start('Analyzing your virtue data with AI...');
const insightData = await this.gatherInsightData();
const insights = await this.generateInsights(insightType, insightData);
s.stop('Analysis complete!');
this.displayInsights(insights, insightType);
outro(picocolors.green('✨ Keep nurturing your character growth!'));
}
catch (error) {
log.error(`Failed to generate insights: ${error}`);
outro(picocolors.red('Failed to generate insights'));
}
}
async gatherInsightData() {
const rawEntries = this.db.getEntriesForProfile(this.profile.id, 30); // Last 30 days
const entries = this.parseEntries(rawEntries);
const virtues = this.db.getVirtuesForProfile(this.profile.id);
// Calculate analytics
const coherences = entries.map(entry => {
const scores = {};
entry.virtue_scores.forEach((vs) => {
scores[vs.virtue_id] = { want: vs.want_score, pull: vs.pull_score };
});
return calculateCoherence(scores);
});
const averageCoherence = coherences.length > 0
? coherences.reduce((sum, val) => sum + val, 0) / coherences.length
: 0;
// Calculate virtue performance
const virtuePerformance = virtues.map(virtue => {
const virtueEntries = entries.filter(entry => entry.virtue_scores.some((vs) => vs.virtue_id === virtue.id));
const alignments = virtueEntries.map(entry => {
const score = entry.virtue_scores.find((vs) => vs.virtue_id === virtue.id);
return score ? calculateAlignment(score.want_score, score.pull_score) : 0;
}).filter(alignment => alignment > 0);
const avgAlignment = alignments.length > 0
? alignments.reduce((sum, val) => sum + val, 0) / alignments.length
: 0;
return {
virtue: virtue.name,
avgAlignment,
entries: virtueEntries.length
};
}).sort((a, b) => b.avgAlignment - a.avgAlignment);
// Calculate trend
const recentEntries = entries.slice(-7);
const olderEntries = entries.slice(-14, -7);
const recentAvg = this.getAverageCoherence(recentEntries);
const olderAvg = this.getAverageCoherence(olderEntries);
let trendDirection = 'stable';
if (recentAvg > olderAvg + 0.05)
trendDirection = 'improving';
else if (recentAvg < olderAvg - 0.05)
trendDirection = 'declining';
return {
recentEntries: entries.slice(-14), // Last 2 weeks
virtues,
analytics: {
averageCoherence,
virtuePerformance,
trendDirection,
challengingVirtue: virtuePerformance[virtuePerformance.length - 1]?.virtue || 'None',
bestVirtue: virtuePerformance[0]?.virtue || 'None'
}
};
}
parseEntries(rawEntries) {
return rawEntries.map(entry => ({
...entry,
virtue_scores: typeof entry.virtue_scores === 'string'
? JSON.parse(entry.virtue_scores)
: entry.virtue_scores
}));
}
getAverageCoherence(entries) {
if (entries.length === 0)
return 0;
const coherences = entries.map(entry => {
const scores = {};
entry.virtue_scores.forEach((vs) => {
scores[vs.virtue_id] = { want: vs.want_score, pull: vs.pull_score };
});
return calculateCoherence(scores);
});
return coherences.reduce((sum, val) => sum + val, 0) / coherences.length;
}
async generateInsights(type, data) {
const prompt = this.buildInsightPrompt(type, data);
try {
return await this.claudeService.generateInsights(prompt);
}
catch (error) {
throw new Error(`AI insight generation failed: ${error}`);
}
}
buildInsightPrompt(type, data) {
const { analytics, virtues, recentEntries } = data;
let prompt = `You are a wise philosopher and character development coach analyzing someone's virtue tracking data.
PROFILE CONTEXT:
- Name: ${this.profile.name}
- Philosophical Template: ${this.profile.philosophical_template}
- Active Virtues: ${virtues.map(v => `${v.name} (${v.definition})`).join(', ')}
RECENT PERFORMANCE DATA:
- Average Coherence: ${(analytics.averageCoherence * 100).toFixed(1)}%
- Trend: ${analytics.trendDirection}
- Best Virtue: ${analytics.bestVirtue} (${(analytics.virtuePerformance[0]?.avgAlignment * 100 || 0).toFixed(1)}%)
- Most Challenging: ${analytics.challengingVirtue} (${(analytics.virtuePerformance[analytics.virtuePerformance.length - 1]?.avgAlignment * 100 || 0).toFixed(1)}%)
- Recent Entries: ${recentEntries.length} in the last 2 weeks
VIRTUE PERFORMANCE BREAKDOWN:
${analytics.virtuePerformance.map(vp => `- ${vp.virtue}: ${(vp.avgAlignment * 100).toFixed(1)}% alignment (${vp.entries} entries)`).join('\n')}
`;
switch (type) {
case 'personal':
prompt += `
TASK: Provide personalized growth insights focusing on:
1. Celebrate their strongest virtues and explain why they're succeeding
2. Offer compassionate guidance for their most challenging virtue
3. Identify unique patterns in their virtue development
4. Suggest ways to build on their natural strengths
5. Provide encouragement tailored to their progress
Be warm, supportive, and specific to their data. Use their actual virtue names and performance.`;
break;
case 'patterns':
prompt += `
TASK: Analyze hidden patterns in their virtue data:
1. Identify correlations between different virtues
2. Spot timing patterns (when they perform best/worst)
3. Recognize behavioral patterns from their coherence trends
4. Highlight interesting relationships in their virtue scores
5. Predict potential future challenges or opportunities
Be analytical but accessible. Focus on actionable pattern recognition.`;
break;
case 'interventions':
prompt += `
TASK: Provide specific, actionable interventions:
1. Design 3-5 concrete practices to improve their challenging virtue
2. Suggest daily/weekly habits that align with their strengths
3. Recommend philosophical exercises or reflections
4. Propose environmental changes or accountability systems
5. Create a 30-day focused improvement plan
Be practical and specific. Give them clear next steps they can implement immediately.`;
break;
case 'philosophical':
prompt += `
TASK: Offer deep philosophical guidance:
1. Connect their virtue journey to classical wisdom
2. Explore the philosophical implications of their patterns
3. Raise profound questions for self-reflection
4. Discuss how their virtues relate to their template (${this.profile.philosophical_template})
5. Provide wisdom from great philosophers relevant to their situation
Be profound yet accessible. Help them see the deeper meaning in their practice.`;
break;
}
prompt += `
Respond in a warm, encouraging tone as a wise mentor. Use markdown formatting for clarity. Include specific references to their data and virtue names. Aim for 300-500 words.`;
return prompt;
}
displayInsights(insights, type) {
const typeEmojis = {
personal: '🎯',
patterns: '📊',
interventions: '💪',
philosophical: '🏛️'
};
const typeNames = {
personal: 'Personal Growth Analysis',
patterns: 'Pattern Recognition',
interventions: 'Actionable Interventions',
philosophical: 'Philosophical Guidance'
};
console.log('\n' + picocolors.bold(`${typeEmojis[type]} ${typeNames[type]}`));
console.log('═'.repeat(60));
console.log('\n' + insights);
console.log('\n' + '─'.repeat(60));
console.log(picocolors.gray('💡 Tip: Try different insight types for varied perspectives on your growth'));
}
}
//# sourceMappingURL=AIInsights.js.map