version 0.8.1 release, stable release

This commit is contained in:
s41r4j
2025-12-30 19:47:40 +05:30
parent 4a30dd018f
commit e5e4713384
9 changed files with 1609 additions and 200 deletions
+118 -47
View File
@@ -1,4 +1,5 @@
const { color } = require('../utils/colors');
const { Intelligence } = require('../utils/intelligence');
/**
* Enhanced git analysis and insights
@@ -6,17 +7,22 @@ const { color } = require('../utils/colors');
class GitAnalyzer {
constructor(git) {
this.git = git;
this.intelligence = new Intelligence(git);
}
async getEnhancedStatus() {
try {
const status = await this.git.status();
const insights = await this.generateStatusInsights(status);
const sessionStats = await this.intelligence.getSessionStats();
const branchContext = await this.intelligence.detectBranchContext();
return {
...status,
insights,
summary: this.generateStatusSummary(status)
summary: this.generateStatusSummary(status),
sessionStats,
branchContext,
};
} catch (error) {
throw new Error(`Failed to get git status: ${error.message}`);
@@ -32,47 +38,48 @@ class GitAnalyzer {
const untracked = Array.isArray(status.not_added) ? status.not_added : [];
if (files.length === 0) return 'Working tree clean';
const parts = [];
if (staged.length > 0) parts.push(`${staged.length} staged`);
if (modified.length > 0) parts.push(`${modified.length} modified`);
if (created.length > 0) parts.push(`${created.length} new`);
if (deleted.length > 0) parts.push(`${deleted.length} deleted`);
if (untracked.length > 0) parts.push(`${untracked.length} untracked`);
return parts.join(', ');
}
async generateStatusInsights(status) {
const insights = [];
// Ensure arrays exist and have proper methods
const modified = Array.isArray(status.modified) ? status.modified : [];
const created = Array.isArray(status.created) ? status.created : [];
const deleted = Array.isArray(status.deleted) ? status.deleted : [];
const files = Array.isArray(status.files) ? status.files : [];
const staged = Array.isArray(status.staged) ? status.staged : [];
// Check for common patterns
if (modified.some(f => String(f).includes('package.json'))) {
insights.push('📦 Dependencies may have changed - consider updating package-lock.json');
}
if (created.some(f => String(f).includes('.env'))) {
insights.push('🔐 New environment file detected - ensure it\'s in .gitignore');
}
if (modified.some(f => String(f).includes('README'))) {
insights.push('📚 Documentation updated - good practice!');
}
if (deleted.length > created.length + modified.length) {
insights.push('🧹 Cleanup operation detected - removing more than adding');
}
if (files.length > 20) {
insights.push('📊 Large changeset - consider breaking into smaller commits');
insights.push('📊 Large changeset - consider using `g split` to break into smaller commits');
}
// Check for test files
const testFiles = files.filter(f => {
const fileName = String(f);
@@ -81,7 +88,7 @@ class GitAnalyzer {
if (testFiles.length > 0) {
insights.push('🧪 Test files modified - great for code quality!');
}
// Check for config files
const configFiles = files.filter(f => {
const fileName = String(f);
@@ -90,7 +97,12 @@ class GitAnalyzer {
if (configFiles.length > 0) {
insights.push('⚙️ Configuration changes detected');
}
// Suggest staging if nothing staged
if (staged.length === 0 && files.length > 0) {
insights.push('💡 Nothing staged yet - use `g o --all` to stage and commit everything');
}
return insights;
}
@@ -98,7 +110,11 @@ class GitAnalyzer {
try {
const log = await this.git.log({ maxCount: limit });
const commits = log.all;
if (commits.length === 0) {
return { totalCommits: 0 };
}
const analysis = {
totalCommits: commits.length,
authors: [...new Set(commits.map(c => c.author_name))],
@@ -106,7 +122,7 @@ class GitAnalyzer {
conventionalCommits: commits.filter(c => /^(feat|fix|docs|style|refactor|test|chore)(\(.+\))?:/.test(c.message)).length,
recentActivity: this.analyzeRecentActivity(commits)
};
return analysis;
} catch (error) {
return { error: error.message };
@@ -117,10 +133,10 @@ class GitAnalyzer {
const now = new Date();
const oneDayAgo = new Date(now - 24 * 60 * 60 * 1000);
const oneWeekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);
const recentCommits = commits.filter(c => new Date(c.date) > oneDayAgo);
const weeklyCommits = commits.filter(c => new Date(c.date) > oneWeekAgo);
return {
last24h: recentCommits.length,
lastWeek: weeklyCommits.length,
@@ -133,16 +149,20 @@ class GitAnalyzer {
const additions = lines.filter(l => l.startsWith('+')).length;
const deletions = lines.filter(l => l.startsWith('-')).length;
const files = (diff.match(/diff --git/g) || []).length;
let complexity = 'simple';
let emoji = '🟢';
if (files > 10 || additions + deletions > 500) {
complexity = 'complex';
emoji = '🔴';
} else if (files > 5 || additions + deletions > 100) {
complexity = 'moderate';
emoji = '🟡';
}
return {
complexity,
emoji,
files,
additions,
deletions,
@@ -151,81 +171,132 @@ class GitAnalyzer {
}
formatStatusOutput(enhancedStatus) {
const {
files = [],
staged = [],
modified = [],
created = [],
deleted = [],
not_added = [],
insights = [],
summary = 'Unknown status'
const {
files = [],
staged = [],
modified = [],
created = [],
deleted = [],
not_added = [],
insights = [],
summary = 'Unknown status',
sessionStats = {},
branchContext = {},
} = enhancedStatus;
let output = '';
// Header
output += `${color.bold('Git Status')}\n`;
output += `${color.dim(summary)}\n\n`;
// Header with branch info
output += `${color.bold('Git Status')}`;
if (branchContext.branch) {
output += ` ${color.dim('on')} ${color.cyan(branchContext.branch)}`;
if (branchContext.type) {
output += ` ${color.dim(`(${branchContext.type})`)}`;
}
}
output += '\n';
output += `${color.dim(summary)}\n`;
// Session stats
if (sessionStats.timeSinceLastCommit) {
output += `${color.dim(`Last commit: ${sessionStats.timeSinceLastCommit}`)}`;
if (sessionStats.commitsToday > 0) {
output += `${color.dim(`${sessionStats.commitsToday} commit${sessionStats.commitsToday > 1 ? 's' : ''} today`)}`;
}
output += '\n';
}
output += '\n';
// Staged changes
if (staged.length > 0) {
output += `${color.green('Staged for commit:')}\n`;
staged.forEach(file => {
output += ` ${color.green('+')} ${file}\n`;
const emoji = Intelligence.getFileEmoji(file);
output += ` ${color.green('+')} ${emoji} ${file}\n`;
});
output += '\n';
}
// Modified files
if (modified.length > 0) {
output += `${color.yellow('Modified (not staged):')}\n`;
modified.forEach(file => {
output += ` ${color.yellow('M')} ${file}\n`;
const emoji = Intelligence.getFileEmoji(file);
output += ` ${color.yellow('M')} ${emoji} ${file}\n`;
});
output += '\n';
}
// New files
if (created.length > 0) {
output += `${color.cyan('New files:')}\n`;
created.forEach(file => {
output += ` ${color.cyan('N')} ${file}\n`;
const emoji = Intelligence.getFileEmoji(file);
output += ` ${color.cyan('N')} ${emoji} ${file}\n`;
});
output += '\n';
}
// Deleted files
if (deleted.length > 0) {
output += `${color.red('Deleted:')}\n`;
deleted.forEach(file => {
output += ` ${color.red('D')} ${file}\n`;
const emoji = Intelligence.getFileEmoji(file);
output += ` ${color.red('D')} ${emoji} ${file}\n`;
});
output += '\n';
}
// Untracked files
if (not_added.length > 0) {
output += `${color.dim('Untracked files:')}\n`;
not_added.slice(0, 10).forEach(file => {
output += ` ${color.dim('?')} ${file}\n`;
const emoji = Intelligence.getFileEmoji(file);
output += ` ${color.dim('?')} ${emoji} ${file}\n`;
});
if (not_added.length > 10) {
output += ` ${color.dim(`... and ${not_added.length - 10} more`)}\n`;
}
output += '\n';
}
// AI Insights
if (insights.length > 0) {
output += `${color.cyan('💡 AI Insights:')}\n`;
output += `${color.cyan('💡 Insights:')}\n`;
insights.forEach(insight => {
output += ` ${insight}\n`;
});
}
return output;
}
/**
* Get today's commits formatted nicely
*/
async getTodayCommits() {
try {
const today = new Date();
today.setHours(0, 0, 0, 0);
const log = await this.git.log({ '--since': today.toISOString() });
return log.all;
} catch (error) {
return [];
}
}
/**
* Format commit for display
*/
formatCommit(commit, index) {
const hash = color.yellow(commit.hash.substring(0, 7));
const message = commit.message.split('\n')[0];
const time = new Date(commit.date).toLocaleTimeString('en-US', {
hour: '2-digit',
minute: '2-digit'
});
return ` ${color.dim(`${index + 1}.`)} ${hash} ${message} ${color.dim(`(${time})`)}`;
}
}
module.exports = { GitAnalyzer };