alnilam-cli
Version:
Git-native AI career coach that converts multi-year ambitions into weekly execution
415 lines (414 loc) ⢠19.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.forecastCommand = exports.insightsCommand = exports.trendsCommand = void 0;
const commander_1 = require("commander");
const api_js_1 = require("../lib/api.js");
const asciichart_1 = __importDefault(require("asciichart"));
// Trends command
const trendsCommand = new commander_1.Command('trends');
exports.trendsCommand = trendsCommand;
trendsCommand
.description('Analyze momentum and activity trends over time')
.option('--days <n>', 'Number of days to analyze', '30')
.option('--json', 'Output as JSON')
.action(async (options) => {
try {
const days = parseInt(options.days);
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - days);
console.log('š Momentum & Activity Trends');
console.log('ā'.repeat(50));
// Fetch evaluations and summaries
const [evaluationsResponse, summariesResponse, goalsResponse] = await Promise.all([
api_js_1.restClient.get('/evaluations', {
params: {
select: '*',
'created_at': `gte.${cutoffDate.toISOString()}`,
order: 'created_at.asc'
}
}),
api_js_1.restClient.get('/summaries', {
params: {
select: '*',
'created_at': `gte.${cutoffDate.toISOString()}`,
order: 'created_at.asc'
}
}),
api_js_1.restClient.get('/goals', {
params: {
select: '*',
'created_at': `gte.${cutoffDate.toISOString()}`,
order: 'created_at.asc'
}
})
]);
const evaluations = evaluationsResponse.data || [];
const summaries = summariesResponse.data || [];
const goals = goalsResponse.data || [];
if (options.json) {
console.log(JSON.stringify({
evaluations,
summaries,
goals,
analysis: { period_days: days }
}, null, 2));
return;
}
// Calculate momentum statistics first
let avgMomentum = 0;
let momentumData = [];
// Momentum trend analysis
if (evaluations.length > 0) {
console.log('š Momentum Score Trends:');
console.log('ā'.repeat(30));
momentumData = evaluations.map(evaluation => evaluation.momentum_score || 0);
const chart = asciichart_1.default.plot(momentumData, {
height: 8,
colors: [asciichart_1.default.blue]
});
console.log(chart);
avgMomentum = Math.round(momentumData.reduce((a, b) => a + b, 0) / momentumData.length);
const lastMomentum = momentumData[momentumData.length - 1];
const trend = lastMomentum > avgMomentum ? 'š Improving' : 'š Declining';
console.log(`Average: ${avgMomentum}/100 | Latest: ${lastMomentum}/100 | Trend: ${trend}\n`);
}
// Activity patterns
console.log('š Activity Patterns:');
console.log('ā'.repeat(30));
const activityByDay = Array(7).fill(0);
const dailySummaries = summaries.reduce((acc, summary) => {
const date = new Date(summary.created_at).toDateString();
acc[date] = (acc[date] || 0) + 1;
// Track day of week
const dayOfWeek = new Date(summary.created_at).getDay();
activityByDay[dayOfWeek]++;
return acc;
}, {});
const dayNames = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
const maxActivity = Math.max(...activityByDay);
console.log('Activity by day of week:');
activityByDay.forEach((count, index) => {
const barLength = Math.round((count / maxActivity) * 20);
const bar = 'ā'.repeat(barLength) + 'ā'.repeat(20 - barLength);
console.log(`${dayNames[index]}: [${bar}] ${count}`);
});
// Goal creation trends
console.log('\nšÆ Goal Creation Trends:');
console.log('ā'.repeat(30));
const goalsByHorizon = goals.reduce((acc, goal) => {
acc[goal.horizon] = (acc[goal.horizon] || 0) + 1;
return acc;
}, {});
Object.entries(goalsByHorizon).forEach(([horizon, count]) => {
const emoji = horizon === 'weekly' ? 'š
' :
horizon === 'quarterly' ? 'š' :
horizon === 'annual' ? 'šļø' : 'š';
console.log(`${emoji} ${horizon}: ${count} goals`);
});
// Productivity insights
console.log('\nš” Key Insights:');
console.log('ā'.repeat(30));
const totalDays = Object.keys(dailySummaries).length;
const avgDailyActivity = summaries.length / totalDays;
const mostActiveDay = dayNames[activityByDay.indexOf(maxActivity)];
console.log(`š Active days: ${totalDays}/${days} (${Math.round((totalDays / days) * 100)}%)`);
console.log(`ā” Average daily summaries: ${avgDailyActivity.toFixed(1)}`);
console.log(`š„ Most active day: ${mostActiveDay}`);
if (evaluations.length >= 2) {
const recentMomentum = evaluations.slice(-3).map(e => e.momentum_score || 0);
const avgRecent = recentMomentum.reduce((a, b) => a + b, 0) / recentMomentum.length;
const momentumTrend = avgRecent > avgMomentum ? 'gaining' : 'losing';
console.log(`š Momentum trend: ${momentumTrend} steam (${avgRecent.toFixed(0)} recent vs ${avgMomentum.toFixed(0)} average)`);
}
}
catch (error) {
console.error('ā Trends analysis error:', error.message);
process.exit(1);
}
});
// Insights command
const insightsCommand = new commander_1.Command('insights');
exports.insightsCommand = insightsCommand;
insightsCommand
.description('Generate AI-powered insights from your data patterns')
.option('--weeks <n>', 'Number of weeks to analyze', '4')
.option('--json', 'Output as JSON')
.action(async (options) => {
try {
const weeks = parseInt(options.weeks);
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - (weeks * 7));
console.log('š§ AI-Powered Insights');
console.log('ā'.repeat(50));
// Fetch recent data
const [evaluationsResponse, summariesResponse, goalsResponse, evidenceResponse] = await Promise.all([
api_js_1.restClient.get('/evaluations', {
params: {
select: '*',
'created_at': `gte.${cutoffDate.toISOString()}`,
order: 'created_at.desc',
limit: 10
}
}),
api_js_1.restClient.get('/summaries', {
params: {
select: '*',
'created_at': `gte.${cutoffDate.toISOString()}`,
order: 'created_at.desc'
}
}),
api_js_1.restClient.get('/goals', {
params: {
select: '*',
order: 'created_at.desc'
}
}),
api_js_1.restClient.get('/evidence', {
params: {
select: '*',
'created_at': `gte.${cutoffDate.toISOString()}`,
order: 'created_at.desc'
}
})
]);
const evaluations = evaluationsResponse.data || [];
const summaries = summariesResponse.data || [];
const goals = goalsResponse.data || [];
const evidence = evidenceResponse.data || [];
if (options.json) {
console.log(JSON.stringify({
evaluations,
summaries,
goals,
evidence,
analysis: { period_weeks: weeks }
}, null, 2));
return;
}
// Momentum patterns
console.log('š Momentum Patterns:');
console.log('ā'.repeat(30));
if (evaluations.length >= 2) {
const scores = evaluations.map(e => e.momentum_score || 0);
const avgScore = scores.reduce((a, b) => a + b, 0) / scores.length;
const volatility = Math.sqrt(scores.reduce((acc, score) => acc + Math.pow(score - avgScore, 2), 0) / scores.length);
console.log(`š Average momentum: ${avgScore.toFixed(0)}/100`);
console.log(`š Consistency: ${volatility < 15 ? 'High' : volatility < 25 ? 'Medium' : 'Low'} (volatility: ${volatility.toFixed(1)})`);
if (volatility > 25) {
console.log('š” Consider focusing on consistent daily habits to stabilize momentum');
}
}
// Goal achievement patterns
console.log('\nšÆ Achievement Patterns:');
console.log('ā'.repeat(30));
const completedGoals = goals.filter(g => g.status === 'completed');
const activeGoals = goals.filter(g => g.status === 'active');
const completionRate = goals.length > 0 ? (completedGoals.length / goals.length) * 100 : 0;
console.log(`ā
Completion rate: ${completionRate.toFixed(0)}% (${completedGoals.length}/${goals.length})`);
if (completionRate < 30) {
console.log('š” Focus on smaller, more achievable goals to build momentum');
}
else if (completionRate > 80) {
console.log('š Excellent completion rate! Consider setting more ambitious goals');
}
// Activity consistency
console.log('\nš
Activity Consistency:');
console.log('ā'.repeat(30));
const activeDays = new Set(summaries.map(s => new Date(s.created_at).toDateString())).size;
const totalDays = weeks * 7;
const consistencyRate = (activeDays / totalDays) * 100;
console.log(`š Active days: ${activeDays}/${totalDays} (${consistencyRate.toFixed(0)}%)`);
if (consistencyRate < 50) {
console.log('š” Try setting a daily 5-minute reflection habit to increase consistency');
}
else if (consistencyRate > 80) {
console.log('š„ Outstanding consistency! You\'re building powerful habits');
}
// Evidence collection insights
console.log('\nš Evidence Collection:');
console.log('ā'.repeat(30));
const evidenceByType = evidence.reduce((acc, item) => {
acc[item.type] = (acc[item.type] || 0) + 1;
return acc;
}, {});
const totalEvidence = evidence.length;
console.log(`š Total evidence items: ${totalEvidence}`);
Object.entries(evidenceByType).forEach(([type, count]) => {
console.log(` ⢠${type}: ${count} items`);
});
// Recommendations
console.log('\nšÆ Personalized Recommendations:');
console.log('ā'.repeat(30));
const recommendations = [];
if (activeGoals.length > 3) {
recommendations.push('Focus on 2-3 active goals max to avoid context switching overhead');
}
if (summaries.length < (weeks * 3)) {
recommendations.push('Increase daily reflection frequency - aim for 4+ summaries per week');
}
if (evaluations.length === 0) {
recommendations.push('Schedule weekly momentum evaluations to track progress trends');
}
if (evidence.length < (summaries.length * 0.5)) {
recommendations.push('Collect more evidence - aim for 1-2 evidence items per summary');
}
if (recommendations.length === 0) {
recommendations.push('Great momentum! Consider setting a stretch goal to push your limits');
}
recommendations.forEach((rec, index) => {
console.log(`${index + 1}. š” ${rec}`);
});
}
catch (error) {
console.error('ā Insights analysis error:', error.message);
process.exit(1);
}
});
// Forecast command
const forecastCommand = new commander_1.Command('forecast');
exports.forecastCommand = forecastCommand;
forecastCommand
.description('Predict future momentum and goal completion likelihood')
.option('--horizon <weeks>', 'Forecast horizon in weeks', '4')
.option('--json', 'Output as JSON')
.action(async (options) => {
try {
const horizon = parseInt(options.horizon);
console.log('š® Momentum & Goal Forecast');
console.log('ā'.repeat(50));
// Fetch recent data for forecasting
const cutoffDate = new Date();
cutoffDate.setDate(cutoffDate.getDate() - 28); // 4 weeks history
const [evaluationsResponse, goalsResponse, summariesResponse] = await Promise.all([
api_js_1.restClient.get('/evaluations', {
params: {
select: '*',
'created_at': `gte.${cutoffDate.toISOString()}`,
order: 'created_at.asc'
}
}),
api_js_1.restClient.get('/goals', {
params: {
select: '*',
status: 'eq.active'
}
}),
api_js_1.restClient.get('/summaries', {
params: {
select: '*',
'created_at': `gte.${cutoffDate.toISOString()}`,
order: 'created_at.asc'
}
})
]);
const evaluations = evaluationsResponse.data || [];
const activeGoals = goalsResponse.data || [];
const summaries = summariesResponse.data || [];
if (options.json) {
console.log(JSON.stringify({
evaluations,
activeGoals,
summaries,
forecast: { horizon_weeks: horizon }
}, null, 2));
return;
}
// Momentum forecast
console.log('š Momentum Forecast:');
console.log('ā'.repeat(30));
if (evaluations.length >= 2) {
const scores = evaluations.map(e => e.momentum_score || 0);
const currentMomentum = scores[scores.length - 1];
// Simple linear trend calculation
const trend = scores.length > 1 ? (scores.slice(-3).reduce((a, b) => a + b, 0) / 3) - (scores.slice(-6, -3).reduce((a, b) => a + b, 0) / 3) : 0;
const forecastMomentum = Math.max(0, Math.min(100, currentMomentum + (trend * horizon)));
console.log(`š Current momentum: ${currentMomentum}/100`);
console.log(`š Weekly trend: ${trend > 0 ? '+' : ''}${trend.toFixed(1)} points`);
console.log(`š® Forecast (${horizon} weeks): ${forecastMomentum.toFixed(0)}/100`);
const trendEmoji = trend > 5 ? 'š' : trend > 0 ? 'š' : trend > -5 ? 'ā”ļø' : 'š';
console.log(`${trendEmoji} Trajectory: ${trend > 5 ? 'Accelerating' : trend > 0 ? 'Growing' : trend > -5 ? 'Stable' : 'Declining'}`);
}
else {
console.log('š Not enough momentum data for accurate forecasting');
console.log('š” Complete 2+ weekly evaluations to enable forecasting');
}
// Goal completion forecast
console.log('\nšÆ Goal Completion Forecast:');
console.log('ā'.repeat(30));
if (activeGoals.length > 0) {
activeGoals.forEach((goal, index) => {
const createdDate = new Date(goal.created_at);
const now = new Date();
const ageWeeks = Math.ceil((now.getTime() - createdDate.getTime()) / (1000 * 60 * 60 * 24 * 7));
// Simple heuristic based on goal age and current momentum
const currentMomentum = evaluations.length > 0 ? evaluations[evaluations.length - 1].momentum_score || 50 : 50;
let completionProbability = 0;
if (goal.horizon === 'weekly') {
completionProbability = Math.min(90, currentMomentum + (ageWeeks > 2 ? -20 : 10));
}
else if (goal.horizon === 'quarterly') {
completionProbability = Math.min(80, currentMomentum - (ageWeeks > 8 ? 15 : 0));
}
else if (goal.horizon === 'annual') {
completionProbability = Math.min(70, currentMomentum - 10);
}
else {
completionProbability = Math.min(60, currentMomentum - 20);
}
const probabilityColor = completionProbability > 70 ? 'š¢' :
completionProbability > 40 ? 'š”' : 'š“';
console.log(`${index + 1}. ${goal.title.substring(0, 40)}...`);
console.log(` ${probabilityColor} Completion likelihood: ${Math.max(0, completionProbability).toFixed(0)}%`);
console.log(` š
Age: ${ageWeeks} weeks | š Horizon: ${goal.horizon}`);
});
}
else {
console.log('šÆ No active goals to forecast');
console.log('š” Create goals to see completion predictions');
}
// Activity forecast
console.log('\nš Activity Forecast:');
console.log('ā'.repeat(30));
const recentActivity = summaries.length;
const weeklyActivity = recentActivity / 4; // 4 weeks of history
const forecastActivity = weeklyActivity * horizon;
console.log(`š Recent activity: ${recentActivity} summaries in 4 weeks`);
console.log(`š Weekly average: ${weeklyActivity.toFixed(1)} summaries`);
console.log(`š® Forecast (${horizon} weeks): ${forecastActivity.toFixed(0)} summaries`);
if (weeklyActivity < 3) {
console.log('ā ļø Low activity detected - consider setting daily reflection reminders');
}
else if (weeklyActivity > 7) {
console.log('š„ High activity! Great momentum building');
}
// Risk factors
console.log('\nā ļø Risk Factors:');
console.log('ā'.repeat(30));
const risks = [];
if (evaluations.length > 0) {
const lastMomentum = evaluations[evaluations.length - 1].momentum_score || 0;
if (lastMomentum < 40) {
risks.push('Low momentum score may impact goal completion');
}
}
if (activeGoals.length > 5) {
risks.push('Too many active goals may lead to scattered focus');
}
if (summaries.length < 8) { // Less than 2 per week
risks.push('Inconsistent reflection habit may reduce self-awareness');
}
if (risks.length === 0) {
risks.push('No significant risk factors detected - maintain current trajectory!');
}
risks.forEach((risk, index) => {
console.log(`${index + 1}. ā ļø ${risk}`);
});
}
catch (error) {
console.error('ā Forecast analysis error:', error.message);
process.exit(1);
}
});