virtue-cli
Version:
Personal character development CLI tool for tracking virtues and philosophical alignment
172 lines ⢠6.53 kB
JavaScript
import { Database } from '../database/Database.js';
import { ProfileManager } from './ProfileManager.js';
import { DailyCheckin } from '../commands/DailyCheckin.js';
import { MonthlyDeepDive } from '../commands/MonthlyDeepDive.js';
import { Analytics } from '../commands/Analytics.js';
import { AIInsights } from '../commands/AIInsights.js';
import { DriftDetection } from '../commands/DriftDetection.js';
import { ExportManager } from '../services/ExportManager.js';
import { outro, select, log } from '@clack/prompts';
import { ASCII_LOGO } from '../utils/ascii-art.js';
import { getTheme } from '../utils/themes.js';
export class VirtueTracker {
static instance = null;
db;
profileManager;
currentProfile = null;
theme = getTheme();
isInitialized = false;
constructor() {
this.db = new Database();
this.profileManager = new ProfileManager(this.db);
}
static getInstance() {
if (!VirtueTracker.instance) {
VirtueTracker.instance = new VirtueTracker();
VirtueTracker.setupExitHandlers();
}
return VirtueTracker.instance;
}
static setupExitHandlers() {
const cleanup = () => {
VirtueTracker.destroyInstance();
};
process.on('SIGINT', cleanup);
process.on('SIGTERM', cleanup);
process.on('exit', cleanup);
process.on('uncaughtException', (error) => {
console.error('Uncaught exception:', error);
cleanup();
process.exit(1);
});
}
static destroyInstance() {
if (VirtueTracker.instance) {
VirtueTracker.instance.close();
VirtueTracker.instance = null;
}
}
async initialize() {
if (this.isInitialized) {
return;
}
// Wait for any pending migrations to complete
await this.db.waitForMigrations();
// Load default profile if exists
const profiles = this.db.getAllProfiles();
if (profiles.length > 0) {
this.currentProfile = profiles[0];
}
this.isInitialized = true;
}
async hasExistingProfiles() {
return this.db.hasProfiles();
}
async createFirstProfile() {
const profile = await this.profileManager.createProfile();
this.currentProfile = profile;
}
async handleAction(action) {
if (!this.currentProfile) {
log.error('No profile selected. Please create a profile first.');
return;
}
switch (action) {
case 'daily':
await this.dailyCheckin();
break;
case 'monthly':
await this.monthlyDeepDive();
break;
case 'analytics':
await this.viewAnalytics();
break;
case 'insights':
await this.getAIInsights();
break;
case 'profile':
await this.manageProfiles();
break;
case 'export':
await this.exportData();
break;
case 'quick':
await this.quickCheckin();
break;
case 'drift':
await this.assessPhilosophicalDrift();
break;
default:
log.error('Unknown action');
}
}
async showMainMenu() {
console.clear();
console.log(this.theme.primary(ASCII_LOGO));
if (this.currentProfile) {
const streak = this.db.calculateCurrentStreak(this.currentProfile.id);
const avgCoherence = this.db.calculateAverageCoherence(this.currentProfile.id);
log.info(`\nšÆ Current profile: ${this.theme.primary(this.currentProfile.name)}\n` +
`š Streak: ${this.theme.success(streak + ' days')} | ` +
`Avg Coherence: ${this.theme.success((avgCoherence * 100).toFixed(1) + '%')}\n`);
}
const action = await select({
message: 'What would you like to do today?',
options: [
{ value: 'daily', label: 'š Daily Check-in', hint: 'Track today\'s virtue alignment' },
{ value: 'monthly', label: 'š Monthly Deep-Dive', hint: 'Comprehensive analysis & interventions' },
{ value: 'analytics', label: 'š View Analytics', hint: 'Trends and patterns' },
{ value: 'insights', label: 'š§ AI Insights', hint: 'Personalized recommendations' },
{ value: 'drift', label: 'š§ Drift Assessment', hint: 'Detect philosophical changes over time' },
{ value: 'profile', label: 'š¤ Manage Profiles', hint: 'Switch or create profiles' },
{ value: 'export', label: 'š¤ Export Data', hint: 'Generate markdown files' },
{ value: 'exit', label: 'š Exit', hint: 'Close the application' }
]
});
if (action === 'exit') {
outro(this.theme.muted('See you next time!'));
process.exit(0);
}
await this.handleAction(action);
}
async dailyCheckin() {
const checkin = new DailyCheckin(this.db, this.currentProfile);
await checkin.run();
}
async monthlyDeepDive() {
const deepDive = new MonthlyDeepDive(this.db, this.currentProfile);
await deepDive.run();
}
async quickCheckin() {
const checkin = new DailyCheckin(this.db, this.currentProfile);
await checkin.runQuick();
}
async viewAnalytics() {
const analytics = new Analytics(this.db, this.currentProfile);
await analytics.show();
}
async getAIInsights() {
const insights = new AIInsights(this.db, this.currentProfile);
await insights.generate();
}
async manageProfiles() {
await this.profileManager.manage(this.currentProfile);
// Update current profile after management
const profiles = this.db.getAllProfiles();
if (profiles.length > 0) {
this.currentProfile = profiles[0];
}
}
async exportData() {
const exporter = new ExportManager(this.db);
await exporter.exportMenu(this.currentProfile);
}
async assessPhilosophicalDrift() {
const driftDetection = new DriftDetection(this.db, this.currentProfile);
await driftDetection.run();
}
close() {
this.db.close();
}
}
//# sourceMappingURL=VirtueTracker.js.map