virtue-cli
Version:
Personal character development CLI tool for tracking virtues and philosophical alignment
132 lines • 5.61 kB
JavaScript
import { ExportManager } from './ExportManager.js';
import { writeFileSync, mkdirSync, existsSync } from 'fs';
import { join, resolve } from 'path';
import { formatDate } from '../utils/helpers.js';
import { log } from '@clack/prompts';
export class AutoSaveManager {
db;
exportManager;
constructor(db) {
this.db = db;
this.exportManager = new ExportManager(db);
}
async saveDailyEntry(profile, entry) {
if (!profile.output_directory) {
return; // Auto-save not configured
}
try {
const outputDir = resolve(profile.output_directory);
this.ensureDirectoryExists(outputDir);
// Create subdirectory for daily entries
const dailyDir = join(outputDir, 'daily');
this.ensureDirectoryExists(dailyDir);
// Generate filename: YYYY-MM-DD-daily.md
const filename = `${entry.date}-daily.md`;
const filepath = join(dailyDir, filename);
// Generate markdown content for this specific entry
const content = await this.generateDailyEntryMarkdown(profile, entry);
writeFileSync(filepath, content);
log.success(`Daily entry saved to: ${filepath}`);
}
catch (error) {
log.error(`Failed to auto-save daily entry: ${error}`);
}
}
async saveMonthlyDeepDive(profile, month, analysisData) {
if (!profile.output_directory) {
return; // Auto-save not configured
}
try {
const outputDir = resolve(profile.output_directory);
this.ensureDirectoryExists(outputDir);
// Create subdirectory for monthly entries
const monthlyDir = join(outputDir, 'monthly');
this.ensureDirectoryExists(monthlyDir);
// Generate filename: YYYY-MM-monthly.md
const filename = `${month}-monthly.md`;
const filepath = join(monthlyDir, filename);
// Generate markdown content for the monthly analysis
const content = await this.generateMonthlyMarkdown(profile, month, analysisData);
writeFileSync(filepath, content);
log.success(`Monthly deep-dive saved to: ${filepath}`);
}
catch (error) {
log.error(`Failed to auto-save monthly deep-dive: ${error}`);
}
}
ensureDirectoryExists(dirPath) {
if (!existsSync(dirPath)) {
mkdirSync(dirPath, { recursive: true });
}
}
async generateDailyEntryMarkdown(profile, entry) {
const virtues = this.db.getVirtuesForProfile(profile.id);
const scores = JSON.parse(entry.virtue_scores);
let content = `# Daily Virtue Check-in\n\n`;
content += `**Date:** ${formatDate(new Date(entry.date))}\n`;
content += `**Profile:** ${profile.name}\n`;
content += `**Overall Coherence:** ${(entry.coherence_score * 100).toFixed(1)}%\n\n`;
content += `## Virtue Scores\n\n`;
for (const virtue of virtues) {
const score = scores[virtue.id];
if (score) {
const alignment = this.calculateAlignment(score.want, score.pull);
content += `### ${virtue.emoji} ${virtue.name}\n`;
content += `- **Want:** ${score.want}/10\n`;
content += `- **Pull:** ${score.pull}/10\n`;
content += `- **Alignment:** ${(alignment * 100).toFixed(1)}%\n\n`;
}
}
if (entry.notes) {
content += `## Notes\n\n${entry.notes}\n\n`;
}
content += `---\n`;
content += `*Generated by Virtue CLI on ${new Date().toLocaleString()}*\n`;
return content;
}
async generateMonthlyMarkdown(profile, month, analysisData) {
let content = `# Monthly Deep-Dive Analysis\n\n`;
content += `**Month:** ${month}\n`;
content += `**Profile:** ${profile.name}\n`;
content += `**Generated:** ${new Date().toLocaleString()}\n\n`;
if (analysisData.insights) {
content += `## Key Insights\n\n`;
for (const insight of (analysisData.insights || [])) {
content += `- ${insight}\n`;
}
content += `\n`;
}
if (analysisData.virtueAnalysis) {
content += `## Virtue Analysis\n\n`;
for (const [virtueId, analysis] of Object.entries(analysisData.virtueAnalysis)) {
const virtue = this.db.getVirtue(virtueId);
if (virtue && analysis) {
content += `### ${virtue.emoji} ${virtue.name}\n`;
content += `${analysis}\n\n`;
}
}
}
if (analysisData.recommendations) {
content += `## Recommendations\n\n`;
for (const rec of (analysisData.recommendations || [])) {
content += `- ${rec}\n`;
}
content += `\n`;
}
if (analysisData.interventionPlan) {
content += `## Intervention Plan\n\n`;
content += `${analysisData.interventionPlan}\n\n`;
}
content += `---\n`;
content += `*Generated by Virtue CLI on ${new Date().toLocaleString()}*\n`;
return content;
}
calculateAlignment(want, pull) {
if (want === 0 && pull === 0)
return 1;
const maxPossibleDifference = 10;
const actualDifference = Math.abs(want - pull);
return 1 - (actualDifference / maxPossibleDifference);
}
}
//# sourceMappingURL=AutoSaveManager.js.map