166 lines
5.2 KiB
TypeScript
166 lines
5.2 KiB
TypeScript
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 }
|
|
);
|
|
}
|
|
}
|
|
|