@codervisor/devlog-ai
Version:
AI Chat History Extractor & Docker-based Automation - TypeScript implementation for GitHub Copilot and other AI coding assistants with automated testing capabilities
117 lines (116 loc) • 4.56 kB
JavaScript
/**
* Chat Import Service
*
* Service for importing chat history from AI assistants and converting
* them to the devlog system format.
*/
import { CopilotParser } from '../parsers/copilot/copilot-parser.js';
export class DefaultChatImportService {
storageProvider;
constructor(storageProvider) {
this.storageProvider = storageProvider;
}
async importFromCopilot() {
const importId = this.generateImportId();
const progress = {
importId,
status: 'running',
source: 'github-copilot',
progress: {
totalSessions: 0,
processedSessions: 0,
totalMessages: 0,
processedMessages: 0,
percentage: 0,
},
startedAt: new Date().toISOString(),
};
try {
// Use CopilotParser to discover chat data
const parser = new CopilotParser();
const workspaceData = await parser.discoverChatData();
progress.progress.totalSessions = workspaceData.chat_sessions.length;
// Convert to core format
const coreSessions = this.convertToCoreChatSessions(workspaceData);
const coreMessages = this.convertToCoreMessages(workspaceData.chat_sessions);
progress.progress.totalMessages = coreMessages.length;
// Save to storage
for (const session of coreSessions) {
await this.storageProvider.saveChatSession(session);
progress.progress.processedSessions++;
}
if (coreMessages.length > 0) {
await this.storageProvider.saveChatMessages(coreMessages);
progress.progress.processedMessages = coreMessages.length;
}
progress.progress.percentage = 100;
progress.status = 'completed';
progress.completedAt = new Date().toISOString();
progress.results = {
importedSessions: coreSessions.length,
importedMessages: coreMessages.length,
linkedSessions: 0,
errors: 0,
warnings: [],
};
return progress;
}
catch (error) {
progress.status = 'failed';
progress.completedAt = new Date().toISOString();
progress.error = {
message: error instanceof Error ? error.message : 'Unknown error',
details: { stack: error instanceof Error ? error.stack : undefined },
};
throw error;
}
}
async importFromSource(source, config) {
switch (source) {
case 'github-copilot':
return this.importFromCopilot();
default:
throw new Error(`Unsupported chat source: ${source}`);
}
}
convertToCoreChatSessions(workspaceData) {
return workspaceData.chat_sessions.map((session, index) => ({
id: session.session_id || `imported_${Date.now()}_${index}`,
agent: session.agent,
timestamp: session.timestamp.toISOString(),
workspace: session.workspace,
workspacePath: session.workspace,
title: `Chat Session ${session.session_id?.slice(0, 8) || index}`,
status: 'imported',
messageCount: session.messages.length,
duration: undefined,
metadata: session.metadata,
tags: [],
importedAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
linkedDevlogs: [],
archived: false,
}));
}
convertToCoreMessages(sessions) {
const messages = [];
for (const session of sessions) {
session.messages.forEach((message, index) => {
messages.push({
id: message.id || `msg_${Date.now()}_${index}`,
sessionId: session.session_id || `session_${Date.now()}`,
role: message.role,
content: message.content,
timestamp: message.timestamp.toISOString(),
sequence: index,
metadata: message.metadata,
searchContent: message.content.toLowerCase().replace(/[^\w\s]/g, ' '),
});
});
}
return messages;
}
generateImportId() {
return `import_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
}
}