VIBN Frontend for Coolify deployment
This commit is contained in:
165
app/api/projects/[projectId]/complete-history/route.ts
Normal file
165
app/api/projects/[projectId]/complete-history/route.ts
Normal file
@@ -0,0 +1,165 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getApiUrl } from '@/lib/utils/api-url';
|
||||
|
||||
/**
|
||||
* Complete Chronological History
|
||||
* Returns ALL project data in a single chronological timeline
|
||||
* Optimized for AI consumption - no truncation, no summaries
|
||||
*/
|
||||
export async function GET(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ projectId: string }> }
|
||||
) {
|
||||
try {
|
||||
const { projectId } = await params;
|
||||
|
||||
// Load all three data sources
|
||||
const [contextRes, gitRes, activityRes, timelineRes] = await Promise.all([
|
||||
fetch(getApiUrl(`/api/projects/${projectId}/context`, request)),
|
||||
fetch(getApiUrl(`/api/projects/${projectId}/git-history`, request)),
|
||||
fetch(getApiUrl(`/api/projects/${projectId}/activity`, request)),
|
||||
fetch(getApiUrl(`/api/projects/${projectId}/timeline`, request))
|
||||
]);
|
||||
|
||||
const context = contextRes.ok ? await contextRes.json() : null;
|
||||
const git = gitRes.ok ? await gitRes.json() : null;
|
||||
const activity = activityRes.ok ? await activityRes.json() : null;
|
||||
const timeline = timelineRes.ok ? await timelineRes.json() : null;
|
||||
|
||||
// Build complete chronological event stream
|
||||
const events: any[] = [];
|
||||
|
||||
// Add all Git commits as events
|
||||
if (git?.commits) {
|
||||
for (const commit of git.commits) {
|
||||
events.push({
|
||||
type: 'git_commit',
|
||||
timestamp: new Date(commit.date).toISOString(),
|
||||
date: commit.date.split(' ')[0],
|
||||
data: {
|
||||
hash: commit.hash,
|
||||
author: commit.author,
|
||||
message: commit.message,
|
||||
filesChanged: commit.filesChanged,
|
||||
insertions: commit.insertions,
|
||||
deletions: commit.deletions
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add all extension sessions as events
|
||||
if (activity?.sessions) {
|
||||
for (const session of activity.sessions) {
|
||||
events.push({
|
||||
type: 'extension_session',
|
||||
timestamp: session.startTime,
|
||||
date: new Date(session.startTime).toISOString().split('T')[0],
|
||||
data: {
|
||||
id: session.id,
|
||||
startTime: session.startTime,
|
||||
endTime: session.endTime,
|
||||
duration: session.duration,
|
||||
filesModified: session.filesModified,
|
||||
conversationSummary: session.conversationSummary?.substring(0, 200),
|
||||
conversationSnippets: (session.conversation || []).slice(0, 5).map((msg: any) => ({
|
||||
role: msg.role,
|
||||
message: msg.message?.substring(0, 100),
|
||||
timestamp: msg.timestamp
|
||||
}))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Add Cursor conversations (from recent conversations in context)
|
||||
if (context?.activity?.recentConversations) {
|
||||
for (const conv of context.activity.recentConversations) {
|
||||
events.push({
|
||||
type: 'cursor_conversation',
|
||||
timestamp: conv.createdAt,
|
||||
date: new Date(conv.createdAt).toISOString().split('T')[0],
|
||||
data: {
|
||||
id: conv.id,
|
||||
name: conv.name,
|
||||
createdAt: conv.createdAt,
|
||||
messageCount: conv.recentMessages?.length || 0,
|
||||
recentMessages: conv.recentMessages?.map((msg: any) => ({
|
||||
type: msg.type,
|
||||
text: msg.text?.substring(0, 150),
|
||||
createdAt: msg.createdAt
|
||||
}))
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Sort everything chronologically
|
||||
events.sort((a, b) =>
|
||||
new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()
|
||||
);
|
||||
|
||||
// Group by date for easier consumption
|
||||
const eventsByDate: Record<string, any[]> = {};
|
||||
for (const event of events) {
|
||||
if (!eventsByDate[event.date]) {
|
||||
eventsByDate[event.date] = [];
|
||||
}
|
||||
eventsByDate[event.date].push(event);
|
||||
}
|
||||
|
||||
// Build response
|
||||
const completeHistory = {
|
||||
project: {
|
||||
id: projectId,
|
||||
name: context?.project?.name,
|
||||
vision: context?.project?.vision,
|
||||
githubRepo: context?.project?.githubRepo
|
||||
},
|
||||
|
||||
summary: {
|
||||
totalEvents: events.length,
|
||||
dateRange: {
|
||||
earliest: events[0]?.date,
|
||||
latest: events[events.length - 1]?.date,
|
||||
totalDays: Object.keys(eventsByDate).length
|
||||
},
|
||||
breakdown: {
|
||||
gitCommits: events.filter(e => e.type === 'git_commit').length,
|
||||
extensionSessions: events.filter(e => e.type === 'extension_session').length,
|
||||
cursorConversations: events.filter(e => e.type === 'cursor_conversation').length
|
||||
}
|
||||
},
|
||||
|
||||
chronologicalEvents: events,
|
||||
|
||||
eventsByDate: Object.keys(eventsByDate)
|
||||
.sort()
|
||||
.map(date => ({
|
||||
date,
|
||||
dayOfWeek: new Date(date).toLocaleDateString('en-US', { weekday: 'long' }),
|
||||
eventCount: eventsByDate[date].length,
|
||||
events: eventsByDate[date]
|
||||
})),
|
||||
|
||||
metadata: {
|
||||
generatedAt: new Date().toISOString(),
|
||||
dataComplete: true,
|
||||
includesFullHistory: true
|
||||
}
|
||||
};
|
||||
|
||||
return NextResponse.json(completeHistory);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error generating complete history:', error);
|
||||
return NextResponse.json(
|
||||
{
|
||||
error: 'Failed to generate complete history',
|
||||
details: error instanceof Error ? error.message : String(error)
|
||||
},
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user