devmentorai-server 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +141 -0
- package/dist/chunk-QFZAYHDT.js +241 -0
- package/dist/chunk-QFZAYHDT.js.map +1 -0
- package/dist/cli.js +452 -0
- package/dist/cli.js.map +1 -0
- package/dist/server.js +2704 -0
- package/dist/server.js.map +1 -0
- package/package.json +81 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/server.ts","../src/routes/health.ts","../src/routes/sessions.ts","../src/services/thumbnail-service.ts","../src/routes/chat.ts","../src/services/context-prompt-builder.ts","../src/routes/models.ts","../src/routes/images.ts","../src/routes/tools.ts","../src/services/copilot.service.ts","../src/tools/devops-tools.ts","../src/services/session.service.ts","../src/db/index.ts"],"sourcesContent":["import Fastify from 'fastify';\nimport cors from '@fastify/cors';\nimport { healthRoutes } from './routes/health.js';\nimport { sessionRoutes } from './routes/sessions.js';\nimport { chatRoutes } from './routes/chat.js';\nimport { modelsRoutes } from './routes/models.js';\nimport { imagesRoutes } from './routes/images.js';\nimport { registerToolsRoutes } from './routes/tools.js';\nimport { CopilotService } from './services/copilot.service.js';\nimport { SessionService } from './services/session.service.js';\nimport { initDatabase } from './db/index.js';\nimport { DEFAULT_CONFIG } from '@devmentorai/shared';\n\nconst PORT = parseInt(process.env.DEVMENTORAI_PORT || '', 10) || DEFAULT_CONFIG.DEFAULT_PORT;\nconst HOST = '0.0.0.0';\n\n// Observability mode - enable with DEVMENTORAI_DEBUG=true\nconst DEBUG_MODE = true;\n// const DEBUG_MODE = process.env.DEVMENTORAI_DEBUG === 'true';\n\n/**\n * Truncate long strings for logging\n */\nfunction truncate(str: string | undefined | null, maxLen = 500): string {\n if (!str) return '';\n if (str.length <= maxLen) return str;\n return str.slice(0, maxLen) + `... [truncated ${str.length - maxLen} chars]`;\n}\n\nexport async function createServer() {\n const fastify = Fastify({\n logger: {\n level: DEBUG_MODE ? 'debug' : 'info',\n transport: {\n target: 'pino-pretty',\n options: {\n colorize: true,\n translateTime: 'HH:MM:ss Z',\n ignore: 'pid,hostname',\n },\n },\n },\n });\n\n // Observability middleware - log all requests and responses\n if (DEBUG_MODE) {\n fastify.log.info('🔍 Debug mode enabled - logging all requests and responses');\n \n // Log after body is parsed\n fastify.addHook('preHandler', async (request) => {\n const body = request.body ? truncate(JSON.stringify(request.body)) : null;\n fastify.log.debug({\n type: '→ REQUEST',\n method: request.method,\n url: request.url,\n headers: {\n 'content-type': request.headers['content-type'],\n 'user-agent': request.headers['user-agent'],\n },\n body: body,\n });\n });\n\n fastify.addHook('onSend', async (request, reply, payload) => {\n const statusCode = reply.statusCode;\n let responseBody: string | null = null;\n \n // Skip logging SSE streams (too verbose)\n if (reply.getHeader('content-type') === 'text/event-stream') {\n responseBody = '[SSE Stream]';\n } else if (typeof payload === 'string') {\n responseBody = truncate(payload);\n } else if (Buffer.isBuffer(payload)) {\n responseBody = truncate(payload.toString());\n }\n \n fastify.log.debug({\n type: '← RESPONSE',\n method: request.method,\n url: request.url,\n statusCode,\n body: responseBody,\n });\n \n return payload;\n });\n\n fastify.addHook('onError', async (request, reply, error) => {\n fastify.log.error({\n type: '✗ ERROR',\n method: request.method,\n url: request.url,\n error: error.message,\n stack: error.stack,\n });\n });\n }\n\n // Initialize database\n const db = initDatabase();\n fastify.log.info('Database initialized');\n\n // Initialize services\n const sessionService = new SessionService(db);\n const copilotService = new CopilotService(sessionService);\n \n try {\n await copilotService.initialize();\n fastify.log.info('CopilotService initialized');\n } catch (err) {\n fastify.log.error({ err }, 'Failed to initialize CopilotService');\n fastify.log.warn('Running in mock mode - Copilot features will be simulated');\n }\n\n // Decorate fastify with services\n fastify.decorate('sessionService', sessionService);\n fastify.decorate('copilotService', copilotService);\n\n // Register plugins\n await fastify.register(cors, {\n origin: true, // Allow all origins in development\n methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS'],\n allowedHeaders: ['Content-Type', 'Authorization'],\n });\n\n // Register routes\n await fastify.register(healthRoutes, { prefix: '/api' });\n await fastify.register(sessionRoutes, { prefix: '/api' });\n await fastify.register(chatRoutes, { prefix: '/api' });\n await fastify.register(modelsRoutes, { prefix: '/api' });\n await fastify.register(imagesRoutes, { prefix: '/api/images' });\n \n // Register tools routes (not prefixed - has /api in route definitions)\n registerToolsRoutes(fastify, copilotService);\n\n return fastify;\n}\n\nasync function main() {\n const fastify = await createServer();\n\n // Graceful shutdown\n const shutdown = async () => {\n fastify.log.info('Shutting down...');\n try {\n await fastify.copilotService.shutdown();\n await fastify.close();\n process.exit(0);\n } catch (err) {\n fastify.log.error({ err }, 'Error during shutdown');\n process.exit(1);\n }\n };\n\n process.on('SIGINT', shutdown);\n process.on('SIGTERM', shutdown);\n\n // Start server\n try {\n await fastify.listen({ port: PORT, host: HOST });\n fastify.log.info(`🚀 DevMentorAI backend running at http://${HOST}:${PORT}`);\n } catch (error) {\n fastify.log.error(error);\n process.exit(1);\n }\n}\n\nmain();\n\n// Type augmentation for Fastify\ndeclare module 'fastify' {\n interface FastifyInstance {\n sessionService: SessionService;\n copilotService: CopilotService;\n }\n}\n","import type { FastifyInstance } from 'fastify';\nimport type { ApiResponse, HealthResponse } from '@devmentorai/shared';\n\nconst startTime = Date.now();\n\nexport async function healthRoutes(fastify: FastifyInstance) {\n fastify.get<{\n Reply: ApiResponse<HealthResponse>;\n }>('/health', async (_request, reply) => {\n const copilotService = fastify.copilotService;\n \n const healthData: HealthResponse = {\n status: copilotService.isReady() ? 'healthy' : 'degraded',\n version: '1.0.0',\n copilotConnected: copilotService.isReady() && !copilotService.isMockMode(),\n uptime: Math.floor((Date.now() - startTime) / 1000),\n timestamp: new Date().toISOString(),\n };\n\n return reply.send({\n success: true,\n data: healthData,\n });\n });\n}\n","import type { FastifyInstance } from 'fastify';\nimport { z } from 'zod';\nimport type {\n ApiResponse,\n PaginatedResponse,\n Session,\n CreateSessionRequest,\n UpdateSessionRequest,\n Message,\n} from '@devmentorai/shared';\nimport { deleteSessionImages } from '../services/thumbnail-service.js';\n\nconst createSessionSchema = z.object({\n name: z.string().min(1).max(100),\n type: z.enum(['devops', 'writing', 'development', 'general']),\n model: z.string().optional(),\n systemPrompt: z.string().optional(),\n});\n\nconst updateSessionSchema = z.object({\n name: z.string().min(1).max(100).optional(),\n status: z.enum(['active', 'paused', 'closed']).optional(),\n});\n\nexport async function sessionRoutes(fastify: FastifyInstance) {\n // List sessions\n fastify.get<{\n Querystring: { page?: string; pageSize?: string };\n Reply: ApiResponse<PaginatedResponse<Session>>;\n }>('/sessions', async (request, reply) => {\n const page = parseInt(request.query.page || '1', 10);\n const pageSize = parseInt(request.query.pageSize || '50', 10);\n\n const sessions = fastify.sessionService.listSessions(page, pageSize);\n\n return reply.send({\n success: true,\n data: sessions,\n });\n });\n\n // Create session\n fastify.post<{\n Body: CreateSessionRequest;\n Reply: ApiResponse<Session>;\n }>('/sessions', async (request, reply) => {\n try {\n const body = createSessionSchema.parse(request.body);\n console.log('[sessionRoutes] Creating session with body:', body);\n \n // Create in database\n const session = fastify.sessionService.createSession(body);\n \n // Create Copilot session\n await fastify.copilotService.createCopilotSession(\n session.id,\n session.type,\n session.model,\n session.systemPrompt\n );\n\n return reply.code(201).send({\n success: true,\n data: session,\n });\n } catch (error) {\n if (error instanceof z.ZodError) {\n return reply.code(400).send({\n success: false,\n error: {\n code: 'VALIDATION_ERROR',\n message: 'Invalid request body',\n details: { errors: error.errors },\n },\n });\n }\n throw error;\n }\n });\n\n // Get session\n fastify.get<{\n Params: { id: string };\n Reply: ApiResponse<Session>;\n }>('/sessions/:id', async (request, reply) => {\n const session = fastify.sessionService.getSession(request.params.id);\n\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n return reply.send({\n success: true,\n data: session,\n });\n });\n\n // Update session\n fastify.patch<{\n Params: { id: string };\n Body: UpdateSessionRequest;\n Reply: ApiResponse<Session>;\n }>('/sessions/:id', async (request, reply) => {\n try {\n const body = updateSessionSchema.parse(request.body);\n const session = fastify.sessionService.updateSession(request.params.id, body);\n\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n return reply.send({\n success: true,\n data: session,\n });\n } catch (error) {\n if (error instanceof z.ZodError) {\n return reply.code(400).send({\n success: false,\n error: {\n code: 'VALIDATION_ERROR',\n message: 'Invalid request body',\n details: { errors: error.errors },\n },\n });\n }\n throw error;\n }\n });\n\n // Delete session\n fastify.delete<{\n Params: { id: string };\n Reply: ApiResponse<{ deleted: boolean; sessionId: string }>;\n }>('/sessions/:id', async (request, reply) => {\n const sessionId = request.params.id;\n \n console.log(`[SessionRoute] Deleting session: ${sessionId}`);\n\n // First check if session exists\n const session = fastify.sessionService.getSession(sessionId);\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n // Destroy Copilot session first (handles cleanup of SDK resources)\n try {\n await fastify.copilotService.destroySession(sessionId);\n } catch (error) {\n console.error(`[SessionRoute] Error destroying Copilot session:`, error);\n // Continue with DB deletion even if Copilot cleanup fails\n }\n\n // Clean up images for this session\n try {\n deleteSessionImages(sessionId);\n } catch (error) {\n console.error(`[SessionRoute] Error deleting session images:`, error);\n // Continue with DB deletion even if image cleanup fails\n }\n\n // Delete from database (CASCADE will delete messages)\n const deleted = fastify.sessionService.deleteSession(sessionId);\n \n console.log(`[SessionRoute] Session ${sessionId} deleted: ${deleted}`);\n\n return reply.code(200).send({ \n success: true,\n data: { deleted, sessionId }\n });\n });\n\n // Resume session\n fastify.post<{\n Params: { id: string };\n Reply: ApiResponse<Session>;\n }>('/sessions/:id/resume', async (request, reply) => {\n const sessionId = request.params.id;\n const session = fastify.sessionService.getSession(sessionId);\n\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n // Resume Copilot session\n const resumed = await fastify.copilotService.resumeCopilotSession(sessionId);\n\n if (!resumed) {\n // Create new Copilot session if resume failed\n await fastify.copilotService.createCopilotSession(\n session.id,\n session.type,\n session.model,\n session.systemPrompt\n );\n }\n\n // Update status to active\n const updatedSession = fastify.sessionService.updateSession(sessionId, { status: 'active' });\n\n return reply.send({\n success: true,\n data: updatedSession!,\n });\n });\n\n // Abort request\n fastify.post<{\n Params: { id: string };\n Reply: ApiResponse<void>;\n }>('/sessions/:id/abort', async (request, reply) => {\n await fastify.copilotService.abortRequest(request.params.id);\n\n return reply.send({\n success: true,\n });\n });\n\n // Get session messages\n fastify.get<{\n Params: { id: string };\n Querystring: { page?: string; pageSize?: string };\n Reply: ApiResponse<PaginatedResponse<Message>>;\n }>('/sessions/:id/messages', async (request, reply) => {\n const session = fastify.sessionService.getSession(request.params.id);\n\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n const page = parseInt(request.query.page || '1', 10);\n const pageSize = parseInt(request.query.pageSize || '100', 10);\n\n const messages = fastify.sessionService.listMessages(request.params.id, page, pageSize);\n\n return reply.send({\n success: true,\n data: messages,\n });\n });\n}\n","/**\n * ThumbnailService\n * \n * Handles image processing and thumbnail generation.\n * Stores thumbnails AND full images on disk and provides URLs for serving.\n */\n\nimport sharp from 'sharp';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport {\n getMessageImagesDir,\n getSessionImagesDir,\n getThumbnailPath,\n toRelativePath,\n toImageRelativePath,\n toUrlPath,\n ensureDir,\n deleteDir,\n fileExists,\n} from '../lib/paths.js';\nimport type { ImageAttachment, ImageSource, ImageMimeType } from '@devmentorai/shared';\n\n/** Thumbnail generation settings */\nconst THUMBNAIL_CONFIG = {\n maxDimension: 200,\n quality: 60,\n format: 'jpeg' as const,\n};\n\nexport interface ImageInput {\n id: string;\n dataUrl: string;\n mimeType: ImageMimeType;\n source: ImageSource;\n}\n\nexport interface ProcessedImage {\n id: string;\n source: ImageSource;\n mimeType: ImageMimeType;\n dimensions: { width: number; height: number };\n fileSize: number;\n timestamp: string;\n thumbnailUrl: string;\n /** Relative path for DB storage */\n thumbnailPath: string;\n /** Absolute path to full image (for Copilot SDK attachments) */\n fullImagePath: string;\n /** URL to serve full image to client */\n fullImageUrl: string;\n}\n\n/**\n * Extract base64 data and mime type from a data URL\n */\nfunction parseDataUrl(dataUrl: string): { buffer: Buffer; mimeType: string } | null {\n const match = dataUrl.match(/^data:(image\\/[^;]+);base64,(.+)$/);\n if (!match) return null;\n \n const [, mimeType, base64Data] = match;\n const buffer = Buffer.from(base64Data, 'base64');\n \n return { buffer, mimeType };\n}\n\n/**\n * Get image dimensions from a buffer\n */\nasync function getImageDimensions(buffer: Buffer): Promise<{ width: number; height: number }> {\n const metadata = await sharp(buffer).metadata();\n return {\n width: metadata.width || 0,\n height: metadata.height || 0,\n };\n}\n\n/**\n * Generate a thumbnail from an image buffer\n */\nasync function generateThumbnail(buffer: Buffer): Promise<Buffer> {\n return sharp(buffer)\n .resize(THUMBNAIL_CONFIG.maxDimension, THUMBNAIL_CONFIG.maxDimension, {\n fit: 'inside',\n withoutEnlargement: true,\n })\n .jpeg({ quality: THUMBNAIL_CONFIG.quality })\n .toBuffer();\n}\n\n/**\n * Get the file extension for a MIME type\n */\nfunction getExtensionForMimeType(mimeType: string): string {\n const extensions: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/webp': 'webp',\n 'image/gif': 'gif',\n };\n return extensions[mimeType] || 'jpg';\n}\n\n/**\n * Get the file path for a full image\n */\nexport function getFullImagePath(sessionId: string, messageId: string, index: number, extension: string): string {\n const messageDir = getMessageImagesDir(sessionId, messageId);\n return path.join(messageDir, `image_${index}.${extension}`);\n}\n\n/**\n * Process images for a message, generating and storing thumbnails AND full images\n * \n * @param sessionId - The session ID\n * @param messageId - The message ID\n * @param images - Array of image inputs with data URLs\n * @param backendUrl - Base URL for thumbnail serving\n * @returns Array of processed images with thumbnail URLs and full image paths\n */\nexport async function processMessageImages(\n sessionId: string,\n messageId: string,\n images: ImageInput[],\n backendUrl: string\n): Promise<ProcessedImage[]> {\n if (!images || images.length === 0) return [];\n\n // Ensure the message images directory exists\n const messageDir = getMessageImagesDir(sessionId, messageId);\n ensureDir(messageDir);\n\n const processedImages: ProcessedImage[] = [];\n\n for (let index = 0; index < images.length; index++) {\n const image = images[index];\n \n try {\n // Parse the data URL\n const parsed = parseDataUrl(image.dataUrl);\n if (!parsed) {\n console.error(`[ThumbnailService] Failed to parse data URL for image ${image.id}`);\n continue;\n }\n\n const { buffer, mimeType } = parsed;\n\n // Get original dimensions\n const dimensions = await getImageDimensions(buffer);\n\n // Generate thumbnail\n const thumbnailBuffer = await generateThumbnail(buffer);\n\n // Save thumbnail to disk\n const thumbnailAbsPath = getThumbnailPath(sessionId, messageId, index);\n fs.writeFileSync(thumbnailAbsPath, thumbnailBuffer);\n\n // Save FULL IMAGE to disk (for Copilot SDK attachments and lightbox view)\n const extension = getExtensionForMimeType(mimeType);\n const fullImageAbsPath = getFullImagePath(sessionId, messageId, index, extension);\n fs.writeFileSync(fullImageAbsPath, buffer);\n console.log(`[ThumbnailService] Saved full image to ${fullImageAbsPath}`);\n\n // Generate relative paths for DB storage (from DATA_DIR)\n const thumbnailRelativePath = toRelativePath(thumbnailAbsPath);\n \n // Generate URL paths for serving (from IMAGES_DIR, no \"images/\" prefix)\n const thumbnailUrlPath = toUrlPath(toImageRelativePath(thumbnailAbsPath));\n const fullImageUrlPath = toUrlPath(toImageRelativePath(fullImageAbsPath));\n\n processedImages.push({\n id: image.id,\n source: image.source,\n mimeType: image.mimeType,\n dimensions,\n fileSize: buffer.length,\n timestamp: new Date().toISOString(),\n thumbnailUrl: `${backendUrl}/api/images/${thumbnailUrlPath}`,\n thumbnailPath: thumbnailRelativePath,\n fullImagePath: fullImageAbsPath,\n fullImageUrl: `${backendUrl}/api/images/${fullImageUrlPath}`,\n });\n\n console.log(`[ThumbnailService] Processed image ${index + 1}/${images.length} for message ${messageId}`);\n } catch (error) {\n console.error(`[ThumbnailService] Failed to process image ${image.id}:`, error);\n // Continue with other images even if one fails\n }\n }\n\n return processedImages;\n}\n\n/**\n * Get the absolute path for a thumbnail from URL path segments\n * \n * @param sessionId - The session ID\n * @param messageId - The message ID\n * @param index - The image index\n * @returns Absolute path to the thumbnail file, or null if not found\n */\nexport function getThumbnailFilePath(\n sessionId: string,\n messageId: string,\n index: number\n): string | null {\n const thumbnailPath = getThumbnailPath(sessionId, messageId, index);\n return fileExists(thumbnailPath) ? thumbnailPath : null;\n}\n\n/**\n * Delete all images for a session (cleanup)\n * \n * @param sessionId - The session ID\n */\nexport function deleteSessionImages(sessionId: string): void {\n const sessionDir = getSessionImagesDir(sessionId);\n deleteDir(sessionDir);\n console.log(`[ThumbnailService] Deleted images for session ${sessionId}`);\n}\n\n/**\n * Delete all images for a message (cleanup)\n * \n * @param sessionId - The session ID\n * @param messageId - The message ID\n */\nexport function deleteMessageImages(sessionId: string, messageId: string): void {\n const messageDir = getMessageImagesDir(sessionId, messageId);\n deleteDir(messageDir);\n console.log(`[ThumbnailService] Deleted images for message ${messageId}`);\n}\n\n/**\n * Convert processed images to ImageAttachment format for storage\n */\nexport function toImageAttachments(processedImages: ProcessedImage[]): ImageAttachment[] {\n return processedImages.map(img => ({\n id: img.id,\n source: img.source,\n mimeType: img.mimeType,\n dimensions: img.dimensions,\n fileSize: img.fileSize,\n timestamp: img.timestamp,\n thumbnailUrl: img.thumbnailUrl,\n fullImageUrl: img.fullImageUrl,\n // Note: dataUrl is NOT included - it's only used during processing\n }));\n}\n","import type { FastifyInstance } from 'fastify';\nimport { z } from 'zod';\nimport type { SessionEvent } from '@github/copilot-sdk';\nimport type {\n ApiResponse,\n Message,\n SendMessageRequest,\n StreamEvent,\n ContextPayload,\n ImagePayload,\n ImageAttachment,\n} from '@devmentorai/shared';\nimport {\n buildContextAwarePrompt,\n buildSimplePrompt,\n validateContext,\n sanitizeContext,\n} from '../services/context-prompt-builder.js';\nimport {\n processMessageImages,\n toImageAttachments,\n type ProcessedImage,\n} from '../services/thumbnail-service.js';\n\n// Schema for simple context (backward compatible)\nconst simpleContextSchema = z.object({\n pageUrl: z.string().optional(),\n pageTitle: z.string().optional(),\n selectedText: z.string().optional(),\n action: z.enum([\n 'explain',\n 'translate',\n 'rewrite',\n 'fix_grammar',\n 'summarize',\n 'expand',\n 'analyze_config',\n 'diagnose_error',\n ]).optional(),\n});\n\n// Schema for full context payload\nconst fullContextSchema = z.object({\n metadata: z.object({\n captureTimestamp: z.string(),\n captureMode: z.enum(['auto', 'manual']),\n browserInfo: z.object({\n userAgent: z.string(),\n viewport: z.object({ width: z.number(), height: z.number() }),\n language: z.string(),\n }),\n }),\n page: z.object({\n url: z.string(),\n urlParsed: z.object({\n protocol: z.string(),\n hostname: z.string(),\n pathname: z.string(),\n search: z.string(),\n hash: z.string(),\n }),\n title: z.string(),\n platform: z.object({\n type: z.string(),\n confidence: z.number(),\n indicators: z.array(z.string()),\n specificProduct: z.string().optional(),\n }),\n }),\n text: z.object({\n selectedText: z.string().optional(),\n visibleText: z.string(),\n headings: z.array(z.object({\n level: z.number(),\n text: z.string(),\n })),\n errors: z.array(z.object({\n type: z.enum(['error', 'warning', 'info']),\n message: z.string(),\n source: z.enum(['console', 'ui', 'network', 'dom']).optional(),\n severity: z.enum(['critical', 'high', 'medium', 'low']),\n context: z.string().optional(),\n })),\n metadata: z.object({\n totalLength: z.number(),\n truncated: z.boolean(),\n }),\n }),\n structure: z.object({\n relevantSections: z.array(z.any()),\n errorContainers: z.array(z.any()),\n activeElements: z.any(),\n metadata: z.any(),\n }),\n session: z.object({\n sessionId: z.string(),\n sessionType: z.string(),\n intent: z.object({\n primary: z.string(),\n keywords: z.array(z.string()),\n implicitSignals: z.array(z.string()),\n explicitGoal: z.string().optional(),\n }),\n previousMessages: z.object({\n count: z.number(),\n lastN: z.array(z.any()),\n }),\n }),\n privacy: z.object({\n redactedFields: z.array(z.string()),\n sensitiveDataDetected: z.boolean(),\n consentGiven: z.boolean(),\n dataRetention: z.enum(['session', 'none']),\n }),\n}).passthrough();\n\n// Schema for image payload\nconst imagePayloadSchema = z.object({\n id: z.string(),\n dataUrl: z.string(),\n mimeType: z.enum(['image/png', 'image/jpeg', 'image/webp']),\n source: z.enum(['screenshot', 'paste', 'drop']),\n});\n\nconst sendMessageSchema = z.object({\n prompt: z.string().min(1),\n context: simpleContextSchema.optional(),\n fullContext: fullContextSchema.optional(),\n useContextAwareMode: z.boolean().optional(),\n images: z.array(imagePayloadSchema).max(5).optional(),\n});\n\nexport async function chatRoutes(fastify: FastifyInstance) {\n // Helper to build the appropriate prompt based on context type\n // Returns userPrompt (enriched with context) and promptType\n // systemPrompt is always null - we don't override Copilot's default\n const buildPrompt = (\n body: { prompt: string; context?: any; fullContext?: any; useContextAwareMode?: boolean }\n ): { userPrompt: string; promptType: string } => {\n // If full context is provided and context-aware mode is enabled\n if (body.fullContext && body.useContextAwareMode !== false) {\n if (validateContext(body.fullContext)) {\n const sanitizedContext = sanitizeContext(body.fullContext as ContextPayload);\n const { userPrompt } = buildContextAwarePrompt(sanitizedContext, body.prompt);\n return { userPrompt, promptType: 'context-aware' };\n }\n }\n \n // Fall back to simple prompt\n const { userPrompt } = buildSimplePrompt(\n body.prompt,\n body.context?.pageUrl,\n body.context?.pageTitle,\n body.context?.selectedText\n );\n return { userPrompt, promptType: 'simple' };\n };\n\n // Send message (non-streaming)\n fastify.post<{\n Params: { id: string };\n Body: SendMessageRequest;\n Reply: ApiResponse<Message>;\n }>('/sessions/:id/chat', async (request, reply) => {\n try {\n const body = sendMessageSchema.parse(request.body);\n const sessionId = request.params.id;\n\n const session = fastify.sessionService.getSession(sessionId);\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n // Build the prompt (enriched with context, no system prompt override)\n const { userPrompt, promptType } = buildPrompt(body);\n console.log(`[ChatRoute] Using ${promptType} prompt`);\n\n // Save user message\n const userMessage = fastify.sessionService.addMessage(\n sessionId,\n 'user',\n body.prompt,\n body.context ? {\n pageUrl: body.context.pageUrl,\n selectedText: body.context.selectedText,\n action: body.context.action,\n } : undefined\n );\n\n // Persist context if fullContext is provided (Phase 5)\n if (body.fullContext) {\n try {\n fastify.sessionService.saveContext(\n sessionId,\n JSON.stringify(body.fullContext),\n userMessage.id,\n body.fullContext.page?.url,\n body.fullContext.page?.title,\n body.fullContext.page?.platform?.type\n );\n console.log(`[ChatRoute] Context saved for message ${userMessage.id}`);\n } catch (err) {\n console.error('[ChatRoute] Failed to persist context:', err);\n }\n }\n\n // Get response from Copilot (no system prompt - uses customAgents from session)\n const response = await fastify.copilotService.sendMessage(\n sessionId,\n userPrompt,\n body.context\n // NOT passing systemPrompt - preserves Copilot's intelligence\n );\n\n // Save assistant message\n const assistantMessage = fastify.sessionService.addMessage(\n sessionId,\n 'assistant',\n response\n );\n\n return reply.send({\n success: true,\n data: assistantMessage,\n });\n } catch (error) {\n if (error instanceof z.ZodError) {\n return reply.code(400).send({\n success: false,\n error: {\n code: 'VALIDATION_ERROR',\n message: 'Invalid request body',\n details: { errors: error.errors },\n },\n });\n }\n throw error;\n }\n });\n\n // Send message (streaming via SSE)\n fastify.post<{\n Params: { id: string };\n Body: SendMessageRequest;\n }>('/sessions/:id/chat/stream', async (request, reply) => {\n try {\n const body = sendMessageSchema.parse(request.body);\n const sessionId = request.params.id;\n\n const session = fastify.sessionService.getSession(sessionId);\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n // Build the prompt (enriched with context, no system prompt override)\n const { userPrompt, promptType } = buildPrompt(body);\n console.log(`[ChatRoute] Using ${promptType} prompt for streaming`);\n\n // Process images if provided\n let processedImagesRaw: ProcessedImage[] = [];\n let processedImages: ImageAttachment[] = [];\n // Build backend URL with port for image serving\n const host = request.headers.host || `${request.hostname}:3847`;\n const backendUrl = `http://${host}`;\n \n // We'll need the message ID before processing images\n // First save the user message without images\n const userMessage = fastify.sessionService.addMessage(\n sessionId,\n 'user',\n body.prompt,\n body.context ? {\n pageUrl: body.context.pageUrl,\n selectedText: body.context.selectedText,\n action: body.context.action,\n contextAware: body.useContextAwareMode,\n } : { contextAware: body.useContextAwareMode }\n );\n\n // Process images after we have the message ID\n if (body.images && body.images.length > 0) {\n try {\n console.log(`[ChatRoute] Processing ${body.images.length} images for message ${userMessage.id}`);\n processedImagesRaw = await processMessageImages(\n sessionId,\n userMessage.id,\n body.images,\n backendUrl\n );\n processedImages = toImageAttachments(processedImagesRaw);\n \n // Update message metadata with images\n fastify.sessionService.updateMessageMetadata(userMessage.id, {\n ...userMessage.metadata,\n images: processedImages,\n });\n \n console.log(`[ChatRoute] Processed ${processedImages.length} images successfully`);\n } catch (err) {\n console.error('[ChatRoute] Failed to process images:', err);\n // Continue without images - don't fail the message\n }\n }\n\n // Build attachments for Copilot SDK from processed images\n const copilotAttachments = processedImagesRaw.map((img, index) => ({\n type: 'file' as const,\n path: img.fullImagePath,\n displayName: `image_${index + 1}.${img.mimeType.split('/')[1] || 'jpg'}`,\n }));\n \n if (copilotAttachments.length > 0) {\n console.log(`[ChatRoute] Built ${copilotAttachments.length} attachments for Copilot:`, copilotAttachments);\n }\n\n // Persist context if fullContext is provided (Phase 5)\n if (body.fullContext) {\n try {\n fastify.sessionService.saveContext(\n sessionId,\n JSON.stringify(body.fullContext),\n userMessage.id,\n body.fullContext.page?.url,\n body.fullContext.page?.title,\n body.fullContext.page?.platform?.type\n );\n console.log(`[ChatRoute] Context saved for message ${userMessage.id}`);\n } catch (err) {\n console.error('[ChatRoute] Failed to persist context:', err);\n }\n }\n\n // Set up SSE\n reply.raw.setHeader('Content-Type', 'text/event-stream');\n reply.raw.setHeader('Cache-Control', 'no-cache');\n reply.raw.setHeader('Connection', 'keep-alive');\n reply.raw.setHeader('Access-Control-Allow-Origin', '*');\n\n let fullContent = '';\n let assistantMessageId: string | null = null;\n let streamEnded = false;\n let lastActivityTime = Date.now();\n\n // Global timeout for the entire streaming operation (2 minutes)\n const STREAM_TIMEOUT_MS = 120000;\n // Idle timeout - if no events received for this duration, consider it stuck\n const IDLE_TIMEOUT_MS = 30000;\n\n const sendSSE = (event: StreamEvent) => {\n if (!streamEnded) {\n reply.raw.write(`data: ${JSON.stringify(event)}\\n\\n`);\n lastActivityTime = Date.now();\n }\n };\n\n const endStream = (reason: string = 'completed') => {\n if (streamEnded) return;\n streamEnded = true;\n \n console.log(`[ChatRoute] Stream ending: ${reason}. Content length: ${fullContent.length}`);\n \n // Save message if we have content\n if (fullContent && !assistantMessageId) {\n const message = fastify.sessionService.addMessage(\n sessionId,\n 'assistant',\n fullContent\n );\n assistantMessageId = message.id;\n }\n\n sendSSE({ type: 'done', data: { messageId: assistantMessageId || undefined, reason } });\n reply.raw.write('data: [DONE]\\n\\n');\n reply.raw.end();\n };\n\n // Create a Promise that resolves when streaming is complete\n const streamComplete = new Promise<void>((resolve) => {\n // Set up global timeout\n const globalTimeout = setTimeout(() => {\n console.warn('[ChatRoute] Global stream timeout reached');\n endStream('timeout');\n fastify.copilotService.abortRequest(sessionId).catch(() => {});\n resolve();\n }, STREAM_TIMEOUT_MS);\n\n // Set up idle timeout check\n const idleCheckInterval = setInterval(() => {\n const idleTime = Date.now() - lastActivityTime;\n if (idleTime > IDLE_TIMEOUT_MS && !streamEnded) {\n console.warn(`[ChatRoute] Stream idle for ${idleTime}ms, ending`);\n endStream('idle_timeout');\n fastify.copilotService.abortRequest(sessionId).catch(() => {});\n resolve();\n }\n }, 5000);\n\n // Handle Copilot events\n const handleEvent = (event: SessionEvent) => {\n if (streamEnded) return;\n \n console.log('[ChatRoute] Received event:', event.type);\n lastActivityTime = Date.now();\n \n switch (event.type) {\n case 'assistant.message_delta':\n fullContent += event.data.deltaContent || '';\n sendSSE({\n type: 'message_delta',\n data: { deltaContent: event.data.deltaContent },\n });\n break;\n\n case 'assistant.message':\n fullContent = event.data.content || fullContent;\n sendSSE({\n type: 'message_complete',\n data: { content: fullContent },\n });\n break;\n\n case 'tool.execution_start':\n sendSSE({\n type: 'tool_start',\n data: {\n toolName: (event.data as any).toolName,\n toolCallId: (event.data as any).toolCallId,\n },\n });\n break;\n\n case 'tool.execution_complete':\n sendSSE({\n type: 'tool_complete',\n data: { toolCallId: (event.data as any).toolCallId },\n });\n break;\n\n case 'session.idle':\n clearTimeout(globalTimeout);\n clearInterval(idleCheckInterval);\n endStream('completed');\n resolve();\n break;\n }\n };\n\n // Start streaming with attachments (no system prompt - uses customAgents from session)\n fastify.copilotService.streamMessage(\n sessionId,\n userPrompt,\n body.context,\n handleEvent,\n copilotAttachments.length > 0 ? copilotAttachments : undefined\n );\n });\n\n // Handle client disconnect\n request.raw.on('close', async () => {\n if (!streamEnded) {\n console.log('[ChatRoute] Client disconnected, aborting');\n streamEnded = true;\n await fastify.copilotService.abortRequest(sessionId);\n reply.raw.end();\n }\n });\n\n // Wait for streaming to complete before allowing Fastify to close the connection\n await streamComplete;\n\n } catch (error) {\n if (error instanceof z.ZodError) {\n return reply.code(400).send({\n success: false,\n error: {\n code: 'VALIDATION_ERROR',\n message: 'Invalid request body',\n details: error.errors,\n },\n });\n }\n \n // Send error via SSE\n const errorEvent: StreamEvent = {\n type: 'error',\n data: { error: error instanceof Error ? error.message : 'Unknown error' },\n };\n reply.raw.write(`data: ${JSON.stringify(errorEvent)}\\n\\n`);\n reply.raw.write('data: [DONE]\\n\\n');\n reply.raw.end();\n }\n });\n\n // Get session context history (Phase 5)\n fastify.get<{\n Params: { id: string };\n Querystring: { limit?: number };\n }>('/sessions/:id/context', async (request, reply) => {\n const sessionId = request.params.id;\n const limit = request.query.limit || 10;\n\n const session = fastify.sessionService.getSession(sessionId);\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n const latestContext = fastify.sessionService.getLatestContext(sessionId);\n const contextHistory = fastify.sessionService.getContextHistory(sessionId, limit);\n const contextCount = fastify.sessionService.getContextCount(sessionId);\n\n return reply.send({\n success: true,\n data: {\n latest: latestContext,\n history: contextHistory,\n totalCount: contextCount,\n },\n });\n });\n\n // Get specific context by ID (Phase 5)\n fastify.get<{\n Params: { id: string; contextId: string };\n }>('/sessions/:id/context/:contextId', async (request, reply) => {\n const { id: sessionId, contextId } = request.params;\n\n const session = fastify.sessionService.getSession(sessionId);\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n const context = fastify.sessionService.getContext(contextId);\n if (!context || context.sessionId !== sessionId) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Context not found',\n },\n });\n }\n\n return reply.send({\n success: true,\n data: {\n ...context,\n contextData: JSON.parse(context.contextJson),\n },\n });\n });\n\n // Cleanup old contexts for a session (Phase 5)\n fastify.post<{\n Params: { id: string };\n Body: { keepCount?: number };\n }>('/sessions/:id/context/cleanup', async (request, reply) => {\n const sessionId = request.params.id;\n const keepCount = request.body?.keepCount || 20;\n\n const session = fastify.sessionService.getSession(sessionId);\n if (!session) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: 'Session not found',\n },\n });\n }\n\n const deletedCount = fastify.sessionService.cleanupOldContexts(sessionId, keepCount);\n\n return reply.send({\n success: true,\n data: {\n deletedCount,\n remainingCount: fastify.sessionService.getContextCount(sessionId),\n },\n });\n });\n}\n","/**\n * Context Prompt Builder Service\n * \n * Builds context-enriched prompts for the Copilot SDK based on extracted page context.\n * \n * PHASE 3 DESIGN PRINCIPLE - AUTONOMOUS AGENT:\n * ============================================\n * 1. We provide PURELY FACTUAL context (what's on the page)\n * 2. We do NOT tell the agent what to do (no \"Task:\" instructions)\n * 3. We do NOT interpret user intent (the LLM decides)\n * 4. We do NOT use keyword matching (multilingual support, agent autonomy)\n * 5. The agent (Copilot) is fully autonomous in deciding:\n * - What the user wants\n * - How to respond \n * - What context is relevant\n * \n * CustomAgents (DevOps Mentor, etc.) are set at session creation and provide\n * domain expertise. This function ONLY adds situational context from the page.\n */\n\nimport type {\n ContextPayload,\n PlatformDetection,\n ExtractedError,\n HTMLSection,\n Heading,\n} from '@devmentorai/shared';\n\n// ============================================================================\n// Platform-Specific Context Notes (Factual, NOT instructions)\n// ============================================================================\n\n/**\n * Platform context notes - FACTUAL ONLY\n * These describe where relevant information can be found, NOT what the agent should do.\n */\nconst PLATFORM_CONTEXT_NOTES: Record<string, string> = {\n azure: `**Platform:** Azure Portal\nCommon diagnostic locations: Activity Log, Diagnose and solve problems, Resource health`,\n\n aws: `**Platform:** AWS Console \nCommon diagnostic locations: CloudTrail, CloudWatch Logs, IAM policies`,\n\n gcp: `**Platform:** Google Cloud Console\nCommon diagnostic locations: Cloud Logging, Error Reporting, IAM bindings`,\n\n github: `**Platform:** GitHub\nCommon diagnostic locations: Actions tab, Issues, Pull Requests`,\n\n gitlab: `**Platform:** GitLab\nCommon diagnostic locations: Pipelines, Merge Requests, Project settings`,\n\n kubernetes: `**Platform:** Kubernetes Dashboard\nCommon diagnostic commands: kubectl logs, kubectl describe, kubectl get events`,\n\n jenkins: `**Platform:** Jenkins\nCommon diagnostic locations: Console output, Pipeline syntax, Agent status`,\n\n datadog: `**Platform:** Datadog\nCommon diagnostic locations: Metric graphs, Alert conditions, Integration status`,\n\n grafana: `**Platform:** Grafana\nCommon diagnostic locations: Query editor, Data source config, Alert rules`,\n\n generic: ``,\n};\n\n// ============================================================================\n// Context Formatting Functions\n// ============================================================================\n\n/**\n * Format page context section for the prompt\n */\nfunction formatPageContext(page: ContextPayload['page']): string {\n const { platform } = page;\n const platformLabel = platform.specificProduct || platform.type.toUpperCase();\n \n let section = `## Page Context\\n`;\n section += `- **Platform:** ${platformLabel}`;\n if (platform.confidence < 0.8) {\n section += ` (confidence: ${Math.round(platform.confidence * 100)}%)`;\n }\n section += '\\n';\n section += `- **URL:** ${page.url}\\n`;\n section += `- **Title:** ${page.title}\\n`;\n \n return section;\n}\n\n/**\n * Format errors section for the prompt - FACTUAL ONLY\n * No severity emojis - the agent interprets severity\n */\nfunction formatErrors(errors: ExtractedError[]): string {\n if (errors.length === 0) return '';\n\n let section = `## Errors and Alerts on Page\\n`;\n section += `${errors.length} issue(s) detected:\\n\\n`;\n\n for (const error of errors) {\n section += `- **[${error.severity.toUpperCase()}]** ${error.message}\\n`;\n if (error.source) section += ` Source: ${error.source}\\n`;\n if (error.context) section += ` Context: ${error.context}\\n`;\n if (error.stackTrace) section += ` Stack: ${error.stackTrace.slice(0, 200)}...\\n`;\n section += '\\n';\n }\n\n return section;\n}\n\n/**\n * Format headings hierarchy for the prompt\n */\nfunction formatHeadings(headings: Heading[]): string {\n if (headings.length === 0) return '';\n\n let section = `## Page Structure (Headings)\\n`;\n for (const heading of headings.slice(0, 10)) {\n const indent = ' '.repeat(heading.level - 1);\n section += `${indent}- ${heading.text}\\n`;\n }\n return section + '\\n';\n}\n\n/**\n * Format relevant HTML sections for the prompt\n */\nfunction formatRelevantSections(sections: HTMLSection[]): string {\n if (sections.length === 0) return '';\n\n let section = `## Relevant UI Elements\\n`;\n for (const s of sections.slice(0, 5)) {\n section += `### ${s.purpose.replace('-', ' ').toUpperCase()}\\n`;\n section += `\\`\\`\\`\\n${s.textContent.slice(0, 300)}\\n\\`\\`\\`\\n\\n`;\n }\n return section;\n}\n\n/**\n * Format code blocks for the prompt (Phase 2)\n */\nfunction formatCodeBlocks(codeBlocks?: HTMLSection[]): string {\n if (!codeBlocks || codeBlocks.length === 0) return '';\n\n let section = `## Code Snippets Found on Page\\n`;\n for (const block of codeBlocks.slice(0, 3)) {\n const lang = block.attributes.detectedLanguage || 'text';\n section += `### ${lang.toUpperCase()}\\n`;\n section += `\\`\\`\\`${lang}\\n${block.textContent.slice(0, 500)}\\n\\`\\`\\`\\n\\n`;\n }\n return section;\n}\n\n/**\n * Format tables for the prompt (Phase 2)\n */\nfunction formatTables(tables?: HTMLSection[]): string {\n if (!tables || tables.length === 0) return '';\n\n let section = `## Data Tables\\n`;\n for (const table of tables.slice(0, 2)) {\n const rows = table.attributes.rowCount || '?';\n const cols = table.attributes.columnCount || '?';\n section += `### Table (${rows} rows × ${cols} cols)\\n`;\n section += `\\`\\`\\`\\n${table.textContent.slice(0, 400)}\\n\\`\\`\\`\\n\\n`;\n }\n return section;\n}\n\n/**\n * Format console logs for the prompt (Phase 2) - FACTUAL ONLY\n */\nfunction formatConsoleLogs(logs?: Array<{ level: string; message: string; timestamp: string; stackTrace?: string }>): string {\n if (!logs || logs.length === 0) return '';\n\n const errors = logs.filter(l => l.level === 'error' || l.level === 'warn');\n if (errors.length === 0) return '';\n\n let section = `## Browser Console Logs\\n`;\n section += `${errors.length} error/warning message(s):\\n\\n`;\n \n for (const log of errors.slice(0, 5)) {\n section += `- **${log.level.toUpperCase()}:** ${log.message.slice(0, 200)}\\n`;\n if (log.stackTrace) {\n section += ` Stack: ${log.stackTrace.slice(0, 150)}...\\n`;\n }\n section += '\\n';\n }\n return section;\n}\n\n/**\n * Format network errors for the prompt (Phase 2) - FACTUAL ONLY\n */\nfunction formatNetworkErrors(errors?: Array<{ url: string; method: string; status?: number; errorMessage?: string }>): string {\n if (!errors || errors.length === 0) return '';\n\n let section = `## Network Requests Failed\\n`;\n section += `${errors.length} failed request(s):\\n\\n`;\n \n for (const err of errors.slice(0, 5)) {\n const status = err.status ? `HTTP ${err.status}` : (err.errorMessage || 'Failed');\n section += `- **${err.method}** ${err.url.slice(0, 80)}${err.url.length > 80 ? '...' : ''}\\n`;\n section += ` Status: ${status}\\n\\n`;\n }\n return section;\n}\n\n/**\n * Format modal content for the prompt (Phase 2)\n */\nfunction formatModalContent(modal?: HTMLSection): string {\n if (!modal) return '';\n\n let section = `## Active Modal/Dialog\\n`;\n const title = modal.attributes.title || 'Modal';\n section += `### ${title}\\n`;\n section += `\\`\\`\\`\\n${modal.textContent.slice(0, 400)}\\n\\`\\`\\`\\n\\n`;\n return section;\n}\n\n/**\n * Format platform-specific context for the prompt (Phase 2)\n */\nfunction formatPlatformSpecificContext(platformContext?: Record<string, unknown>): string {\n if (!platformContext || Object.keys(platformContext).length === 0) return '';\n\n let section = `## Platform-Specific Details\\n`;\n for (const [key, value] of Object.entries(platformContext)) {\n if (value !== undefined && value !== null) {\n section += `- **${key}:** ${String(value)}\\n`;\n }\n }\n return section + '\\n';\n}\n\n/**\n * Format UI state for the prompt\n */\nfunction formatUIState(uiState: {\n pageState: string;\n loadingIndicators: number;\n disabledButtons: number;\n emptyStates: number;\n errorStates: number;\n toastNotifications: number;\n modalOpen: boolean;\n formValidationErrors: number;\n}): string {\n let section = `## UI State\\n`;\n section += `- **Page State:** ${uiState.pageState}\\n`;\n \n const issues: string[] = [];\n if (uiState.loadingIndicators > 0) issues.push(`${uiState.loadingIndicators} loading indicator(s)`);\n if (uiState.errorStates > 0) issues.push(`${uiState.errorStates} error state(s)`);\n if (uiState.emptyStates > 0) issues.push(`${uiState.emptyStates} empty state(s)`);\n if (uiState.toastNotifications > 0) issues.push(`${uiState.toastNotifications} notification(s)`);\n if (uiState.formValidationErrors > 0) issues.push(`${uiState.formValidationErrors} form validation error(s)`);\n if (uiState.disabledButtons > 0) issues.push(`${uiState.disabledButtons} disabled button(s)`);\n if (uiState.modalOpen) issues.push(`modal/dialog open`);\n \n if (issues.length > 0) {\n section += `- **UI Issues:** ${issues.join(', ')}\\n`;\n }\n \n return section + '\\n';\n}\n\n/**\n * Format runtime JavaScript errors for the prompt\n */\nfunction formatRuntimeErrors(errors: Array<{\n message: string;\n source?: string;\n lineno?: number;\n colno?: number;\n stack?: string;\n type: string;\n}>): string {\n if (errors.length === 0) return '';\n\n let section = `## JavaScript Runtime Errors\\n`;\n section += `${errors.length} runtime error(s) detected:\\n\\n`;\n \n for (const err of errors.slice(0, 5)) {\n const errType = err.type === 'unhandledrejection' ? 'Promise Rejection' : 'JS Error';\n section += `- **${errType}:** ${err.message.slice(0, 200)}\\n`;\n if (err.source) {\n section += ` Source: ${err.source}${err.lineno ? `:${err.lineno}` : ''}${err.colno ? `:${err.colno}` : ''}\\n`;\n }\n if (err.stack) {\n section += ` Stack: ${err.stack.slice(0, 150)}...\\n`;\n }\n section += '\\n';\n }\n return section;\n}\n\n/**\n * Format user selection for the prompt\n */\nfunction formatSelectedText(selectedText?: string): string {\n if (!selectedText) return '';\n \n return `## User Selected Text\\nThe user has highlighted this text on the page:\\n\\`\\`\\`\\n${selectedText}\\n\\`\\`\\`\\n\\n`;\n}\n\n/**\n * Format session history for the prompt - FACTUAL ONLY\n */\nfunction formatSessionHistory(messages: { count: number; lastN: Array<{ role: string; content: string }> }): string {\n if (messages.count === 0 || messages.lastN.length === 0) return '';\n\n let section = `## Recent Conversation (${messages.count} messages total)\\n`;\n for (const msg of messages.lastN) {\n const role = msg.role === 'user' ? 'User' : 'Assistant';\n section += `**${role}:** ${msg.content.slice(0, 200)}${msg.content.length > 200 ? '...' : ''}\\n\\n`;\n }\n return section;\n}\n\n// ============================================================================\n// Main Prompt Builder\n// ============================================================================\n\nexport interface ContextAwarePromptOptions {\n includePlatformNotes?: boolean;\n includeErrors?: boolean;\n includeStructure?: boolean;\n // Phase 2 options\n includeCodeBlocks?: boolean;\n includeTables?: boolean;\n includeConsoleLogs?: boolean;\n includeNetworkErrors?: boolean;\n includeModal?: boolean;\n includePlatformSpecific?: boolean;\n maxContextLength?: number;\n // Phase 3: intentInstructions REMOVED - agent is autonomous\n}\n\nconst DEFAULT_OPTIONS: ContextAwarePromptOptions = {\n includePlatformNotes: true,\n includeErrors: true,\n includeStructure: true,\n // Phase 2 defaults\n includeCodeBlocks: true,\n includeTables: true,\n includeConsoleLogs: true,\n includeNetworkErrors: true,\n includeModal: true,\n includePlatformSpecific: true,\n maxContextLength: 10000, // Increased for Phase 2\n};\n\n/**\n * Build a context-enriched user prompt from extracted page context.\n * \n * PHASE 3 - AUTONOMOUS AGENT DESIGN:\n * ==================================\n * - Returns ONLY factual context (what's on the page)\n * - Does NOT tell the agent what to do\n * - Does NOT interpret user intent\n * - The agent decides everything based on the context and user message\n * \n * CustomAgents (DevOps Mentor, etc.) are set at session creation and provide\n * domain expertise. This function ONLY adds situational context.\n * \n * IMPORTANT: The context comes from the user's authenticated browser session.\n * The agent should use this context to answer questions about private/internal\n * pages that are not publicly accessible.\n */\nexport function buildContextAwarePrompt(\n context: ContextPayload,\n userMessage: string,\n options: ContextAwarePromptOptions = {}\n): { systemPrompt: string | null; userPrompt: string } {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n \n // Build the enriched user prompt with FACTUAL context sections\n let enrichedPrompt = '';\n \n // Context header - explains that this data comes from user's browser\n enrichedPrompt += `# Browser Context (from user's authenticated session)\\n\\n`;\n enrichedPrompt += `The following context was extracted from the user's browser. `;\n enrichedPrompt += `This may include private or authenticated content that is not publicly accessible. `;\n enrichedPrompt += `Use this context to answer the user's question - DO NOT attempt to fetch URLs externally.\\n\\n`;\n\n // Page context (always included)\n enrichedPrompt += formatPageContext(context.page);\n\n // UI State (if available) - helps understand page state\n if ((context.page as any).uiState) {\n enrichedPrompt += formatUIState((context.page as any).uiState);\n }\n\n // Platform-specific notes (factual locations, NOT instructions)\n if (opts.includePlatformNotes) {\n const platformNotes = PLATFORM_CONTEXT_NOTES[context.page.platform.type] || \n PLATFORM_CONTEXT_NOTES.generic;\n if (platformNotes) {\n enrichedPrompt += platformNotes + '\\n\\n';\n }\n }\n\n // Phase 2: Platform-specific context details\n if (opts.includePlatformSpecific && context.page.platform.specificContext) {\n enrichedPrompt += formatPlatformSpecificContext(context.page.platform.specificContext);\n }\n\n // Errors (factual listing)\n if (opts.includeErrors) {\n enrichedPrompt += formatErrors(context.text.errors);\n }\n\n // Console errors\n if (opts.includeConsoleLogs && context.text.consoleLogs) {\n enrichedPrompt += formatConsoleLogs(context.text.consoleLogs);\n }\n\n // Network errors\n if (opts.includeNetworkErrors && context.text.networkErrors) {\n enrichedPrompt += formatNetworkErrors(context.text.networkErrors);\n }\n\n // Runtime JavaScript errors (new)\n if ((context.text as any).runtimeErrors?.length > 0) {\n enrichedPrompt += formatRuntimeErrors((context.text as any).runtimeErrors);\n }\n\n // Selected text (user highlighted something specific)\n enrichedPrompt += formatSelectedText(context.text.selectedText);\n\n // Modal content (if present)\n if (opts.includeModal && context.structure.modal) {\n enrichedPrompt += formatModalContent(context.structure.modal);\n }\n\n // Structure (headings + sections) - helps AI understand page layout\n if (opts.includeStructure) {\n enrichedPrompt += formatHeadings(context.text.headings);\n enrichedPrompt += formatRelevantSections(context.structure.relevantSections);\n }\n\n // Code blocks\n if (opts.includeCodeBlocks && context.structure.codeBlocks) {\n enrichedPrompt += formatCodeBlocks(context.structure.codeBlocks);\n }\n\n // Tables\n if (opts.includeTables && context.structure.tables) {\n enrichedPrompt += formatTables(context.structure.tables);\n }\n\n // Session history (for continuity)\n enrichedPrompt += formatSessionHistory(context.session.previousMessages);\n\n // Privacy note\n if (context.privacy?.privacyMaskingApplied) {\n enrichedPrompt += `\\n**Note:** Some sensitive data (${context.privacy.sensitiveDataTypes?.join(', ') || 'various types'}) has been redacted for privacy.\\n\\n`;\n }\n\n // Add the actual user message\n enrichedPrompt += `---\\n\\n## User Message\\n${userMessage}\\n`;\n\n // Truncate if too long\n if (enrichedPrompt.length > (opts.maxContextLength || 10000)) {\n enrichedPrompt = truncatePrompt(enrichedPrompt, opts.maxContextLength || 10000, userMessage);\n }\n\n // Return null for systemPrompt - we don't override Copilot's default\n return { systemPrompt: null, userPrompt: enrichedPrompt };\n}\n\n/**\n * Truncate prompt while preserving the user's actual message\n */\nfunction truncatePrompt(prompt: string, maxLength: number, userMessage: string): string {\n const userMessageSection = `## User Message\\n${userMessage}\\n`;\n const reservedLength = userMessageSection.length + 500; // Reserve space for user message + buffer\n const availableLength = maxLength - reservedLength;\n\n if (availableLength < 500) {\n // Not enough space for context, just return user message\n return userMessageSection;\n }\n\n // Find a good truncation point\n const truncatedContext = prompt.slice(0, availableLength);\n const lastNewline = truncatedContext.lastIndexOf('\\n');\n \n return truncatedContext.slice(0, lastNewline) + '\\n\\n[Context truncated for length]\\n\\n' + userMessageSection;\n}\n\n/**\n * Build a simple prompt without full context (fallback)\n * \n * This also does NOT replace Copilot's system prompt.\n * Just enriches the user message with available context.\n */\nexport function buildSimplePrompt(\n userMessage: string,\n pageUrl?: string,\n pageTitle?: string,\n selectedText?: string\n): { systemPrompt: string | null; userPrompt: string } {\n let userPrompt = '';\n \n // Add any available context to the user message\n if (pageUrl || pageTitle || selectedText) {\n userPrompt += `**Context:**\\n`;\n if (pageUrl) userPrompt += `- Page URL: ${pageUrl}\\n`;\n if (pageTitle) userPrompt += `- Page Title: ${pageTitle}\\n`;\n if (selectedText) userPrompt += `- Selected Text: \"${selectedText.slice(0, 500)}${selectedText.length > 500 ? '...' : ''}\"\\n`;\n userPrompt += '\\n**Question:** ';\n }\n \n userPrompt += userMessage;\n\n // Return null for systemPrompt - we don't override Copilot's default\n return { systemPrompt: null, userPrompt };\n}\n\n/**\n * Validate context payload before using it for prompt building\n */\nexport function validateContext(context: unknown): context is ContextPayload {\n if (!context || typeof context !== 'object') return false;\n \n const c = context as Record<string, unknown>;\n \n // Check required fields\n if (!c.metadata || typeof c.metadata !== 'object') return false;\n if (!c.page || typeof c.page !== 'object') return false;\n if (!c.text || typeof c.text !== 'object') return false;\n if (!c.session || typeof c.session !== 'object') return false;\n \n return true;\n}\n\n/**\n * Sanitize context payload by removing any remaining sensitive data\n */\nexport function sanitizeContext(context: ContextPayload): ContextPayload {\n // Create a deep copy to avoid mutations\n const sanitized = JSON.parse(JSON.stringify(context)) as ContextPayload;\n\n // Additional sanitization patterns\n const sensitivePatterns = [\n /Bearer\\s+[A-Za-z0-9\\-_]+/gi,\n /api[_-]?key[=:]\\s*[A-Za-z0-9\\-_]+/gi,\n /password[=:]\\s*\\S+/gi,\n /token[=:]\\s*[A-Za-z0-9\\-_]+/gi,\n ];\n\n // Sanitize visible text\n let visibleText = sanitized.text.visibleText;\n for (const pattern of sensitivePatterns) {\n visibleText = visibleText.replace(pattern, '[REDACTED]');\n }\n sanitized.text.visibleText = visibleText;\n\n // Sanitize URL query params\n const url = new URL(sanitized.page.url);\n const sensitiveParams = ['token', 'key', 'secret', 'password', 'auth'];\n for (const param of sensitiveParams) {\n if (url.searchParams.has(param)) {\n url.searchParams.set(param, '[REDACTED]');\n }\n }\n sanitized.page.url = url.toString();\n sanitized.page.urlParsed.search = url.search;\n\n return sanitized;\n}\n","import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';\nimport type { ApiResponse } from '@devmentorai/shared';\n\n// D.5 - Model pricing tiers based on user info\ntype PricingTier = 'free' | 'cheap' | 'standard' | 'premium';\n\ninterface Model {\n id: string;\n name: string;\n description: string;\n provider: string;\n isDefault: boolean;\n pricingTier: PricingTier; // D.5\n pricingMultiplier: number; // D.5 - 0 = free, 0.33 = cheap, 1 = standard, 3 = premium\n}\n\n// Available models with pricing info based on user-provided data\nconst AVAILABLE_MODELS: Model[] = [\n // Free tier (0x)\n {\n id: 'gpt-4.1',\n name: 'GPT-4.1',\n description: 'Fast and capable model for most tasks',\n provider: 'openai',\n isDefault: true,\n pricingTier: 'free',\n pricingMultiplier: 0,\n },\n {\n id: 'gpt-4o',\n name: 'GPT-4o',\n description: 'Multimodal model with vision capabilities',\n provider: 'openai',\n isDefault: false,\n pricingTier: 'free',\n pricingMultiplier: 0,\n },\n {\n id: 'gpt-5-mini',\n name: 'GPT-5 Mini',\n description: 'Fast, lightweight model for simple tasks',\n provider: 'openai',\n isDefault: false,\n pricingTier: 'free',\n pricingMultiplier: 0,\n },\n // Cheap tier (0.33x)\n {\n id: 'claude-haiku-4.5',\n name: 'Claude Haiku 4.5',\n description: 'Fast, efficient model for quick tasks',\n provider: 'anthropic',\n isDefault: false,\n pricingTier: 'cheap',\n pricingMultiplier: 0.33,\n },\n {\n id: 'gpt-5.1-codex-mini',\n name: 'GPT-5.1 Codex Mini',\n description: 'Compact coding model',\n provider: 'openai',\n isDefault: false,\n pricingTier: 'cheap',\n pricingMultiplier: 0.33,\n },\n // Standard tier (1x)\n {\n id: 'gpt-5',\n name: 'GPT-5',\n description: 'Most capable model for complex reasoning',\n provider: 'openai',\n isDefault: false,\n pricingTier: 'standard',\n pricingMultiplier: 1,\n },\n {\n id: 'gpt-5.1',\n name: 'GPT-5.1',\n description: 'Enhanced reasoning and analysis',\n provider: 'openai',\n isDefault: false,\n pricingTier: 'standard',\n pricingMultiplier: 1,\n },\n {\n id: 'gpt-5.1-codex',\n name: 'GPT-5.1 Codex',\n description: 'Specialized for code generation',\n provider: 'openai',\n isDefault: false,\n pricingTier: 'standard',\n pricingMultiplier: 1,\n },\n {\n id: 'gpt-5.2',\n name: 'GPT-5.2',\n description: 'Latest generation model',\n provider: 'openai',\n isDefault: false,\n pricingTier: 'standard',\n pricingMultiplier: 1,\n },\n {\n id: 'claude-sonnet-4',\n name: 'Claude Sonnet 4',\n description: 'Balanced model for general use',\n provider: 'anthropic',\n isDefault: false,\n pricingTier: 'standard',\n pricingMultiplier: 1,\n },\n {\n id: 'claude-sonnet-4.5',\n name: 'Claude Sonnet 4.5',\n description: 'Enhanced balanced model',\n provider: 'anthropic',\n isDefault: false,\n pricingTier: 'standard',\n pricingMultiplier: 1,\n },\n {\n id: 'gemini-3-pro-preview',\n name: 'Gemini 3 Pro (Preview)',\n description: 'Google\\'s latest model',\n provider: 'google',\n isDefault: false,\n pricingTier: 'standard',\n pricingMultiplier: 1,\n },\n // Premium tier (3x)\n {\n id: 'claude-opus-4.5',\n name: 'Claude Opus 4.5',\n description: 'Premium model for complex analysis',\n provider: 'anthropic',\n isDefault: false,\n pricingTier: 'premium',\n pricingMultiplier: 3,\n },\n];\n\nexport async function modelsRoutes(fastify: FastifyInstance): Promise<void> {\n // List all available models\n fastify.get<{\n Reply: ApiResponse<{ models: Model[]; default: string }>;\n }>('/models', async (_request: FastifyRequest, reply: FastifyReply) => {\n const defaultModel = AVAILABLE_MODELS.find(m => m.isDefault);\n \n return reply.send({\n success: true,\n data: {\n models: AVAILABLE_MODELS,\n default: defaultModel?.id || 'gpt-4.1',\n },\n });\n });\n\n // Get specific model info\n fastify.get<{\n Params: { id: string };\n Reply: ApiResponse<Model>;\n }>('/models/:id', async (request, reply) => {\n const modelId = request.params.id;\n const model = AVAILABLE_MODELS.find(m => m.id === modelId);\n\n if (!model) {\n return reply.code(404).send({\n success: false,\n error: {\n code: 'NOT_FOUND',\n message: `Model '${modelId}' not found`,\n },\n });\n }\n\n return reply.send({\n success: true,\n data: model,\n });\n });\n}\n","/**\n * Images Route\n * \n * Serves thumbnail and full images stored on disk.\n * Routes:\n * GET /api/images/:sessionId/:messageId/thumb_:index.jpg - Thumbnail\n * GET /api/images/:sessionId/:messageId/image_:index.:ext - Full image\n */\n\nimport type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { IMAGES_DIR } from '../lib/paths.js';\nimport { getThumbnailFilePath } from '../services/thumbnail-service.js';\n\ninterface ImageParams {\n sessionId: string;\n messageId: string;\n filename: string;\n}\n\n// MIME types for supported image formats\nconst MIME_TYPES: Record<string, string> = {\n 'jpg': 'image/jpeg',\n 'jpeg': 'image/jpeg',\n 'png': 'image/png',\n 'webp': 'image/webp',\n 'gif': 'image/gif',\n};\n\nexport async function imagesRoutes(fastify: FastifyInstance) {\n /**\n * GET /api/images/:sessionId/:messageId/:filename\n * Serves thumbnail or full image\n * \n * Filename patterns:\n * - thumb_0.jpg (thumbnail)\n * - image_0.jpg (full image)\n * - image_0.png (full image)\n */\n fastify.get<{ Params: ImageParams }>(\n '/:sessionId/:messageId/:filename',\n async (request: FastifyRequest<{ Params: ImageParams }>, reply: FastifyReply) => {\n const { sessionId, messageId, filename } = request.params;\n\n // Validate session and message IDs (basic security check)\n if (!sessionId?.match(/^session_[a-z0-9]+$/) || !messageId?.match(/^msg_[a-z0-9]+$/)) {\n return reply.code(400).send({ error: 'Invalid session or message ID format' });\n }\n\n // Parse filename - support thumb_N.jpg and image_N.ext\n let filePath: string | null = null;\n let mimeType = 'image/jpeg';\n\n // Check for thumbnail: thumb_0.jpg\n const thumbMatch = filename.match(/^thumb_(\\d+)\\.jpg$/);\n if (thumbMatch) {\n const imageIndex = parseInt(thumbMatch[1], 10);\n filePath = getThumbnailFilePath(sessionId, messageId, imageIndex);\n mimeType = 'image/jpeg';\n }\n\n // Check for full image: image_0.jpg, image_0.png, etc.\n const imageMatch = filename.match(/^image_(\\d+)\\.(jpg|jpeg|png|webp|gif)$/i);\n if (imageMatch) {\n const ext = imageMatch[2].toLowerCase();\n mimeType = MIME_TYPES[ext] || 'image/jpeg';\n // Build path directly\n filePath = path.join(IMAGES_DIR, sessionId, messageId, filename);\n }\n\n if (!filePath) {\n return reply.code(400).send({ error: 'Invalid filename format' });\n }\n\n // Check if file exists\n if (!fs.existsSync(filePath)) {\n console.log(`[ImagesRoute] File not found: ${filePath}`);\n return reply.code(404).send({ error: 'Image not found' });\n }\n\n // Read and send the file\n try {\n const fileBuffer = fs.readFileSync(filePath);\n \n return reply\n .code(200)\n .header('Content-Type', mimeType)\n .header('Cache-Control', 'public, max-age=31536000, immutable') // Cache for 1 year\n .header('Content-Length', fileBuffer.length)\n .send(fileBuffer);\n } catch (error) {\n console.error('[ImagesRoute] Failed to read image file:', error);\n return reply.code(500).send({ error: 'Failed to read image' });\n }\n }\n );\n}\n","/**\n * Tools API Routes\n * \n * Exposes custom DevOps tools for direct execution\n * and provides tool metadata for the extension.\n */\n\nimport type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';\nimport type { CopilotService } from '../services/copilot.service.js';\nimport type { SessionType } from '@devmentorai/shared';\n\ninterface ToolExecuteBody {\n toolName: string;\n params: Record<string, unknown>;\n}\n\nexport function registerToolsRoutes(\n app: FastifyInstance, \n copilotService: CopilotService\n): void {\n \n // List available tools\n app.get('/api/tools', async (\n request: FastifyRequest<{ Querystring: { type?: SessionType } }>,\n reply: FastifyReply\n ) => {\n const sessionType = request.query.type || 'devops';\n const tools = copilotService.getAvailableTools(sessionType);\n \n return reply.send({\n success: true,\n data: tools,\n });\n });\n \n // Execute a tool directly\n app.post('/api/tools/execute', async (\n request: FastifyRequest<{ Body: ToolExecuteBody }>,\n reply: FastifyReply\n ) => {\n const { toolName, params } = request.body;\n \n if (!toolName) {\n return reply.status(400).send({\n success: false,\n error: 'toolName is required',\n });\n }\n \n const result = await copilotService.executeTool(toolName, params || {});\n \n if (!result.success) {\n return reply.status(400).send({\n success: false,\n error: result.error,\n });\n }\n \n return reply.send({\n success: true,\n data: {\n toolName,\n result: result.result,\n },\n });\n });\n \n // Analyze config endpoint (convenience wrapper)\n app.post('/api/tools/analyze-config', async (\n request: FastifyRequest<{ Body: { content: string; type?: string } }>,\n reply: FastifyReply\n ) => {\n const { content, type } = request.body;\n \n if (!content) {\n return reply.status(400).send({\n success: false,\n error: 'content is required',\n });\n }\n \n const result = await copilotService.executeTool('analyze_config', {\n content,\n type: type || 'auto',\n });\n \n return reply.send({\n success: result.success,\n data: result.result,\n error: result.error,\n });\n });\n \n // Analyze error endpoint (convenience wrapper)\n app.post('/api/tools/analyze-error', async (\n request: FastifyRequest<{ Body: { error: string; context?: string } }>,\n reply: FastifyReply\n ) => {\n const { error, context } = request.body;\n \n if (!error) {\n return reply.status(400).send({\n success: false,\n error: 'error is required',\n });\n }\n \n const result = await copilotService.executeTool('analyze_error', {\n error,\n context: context || 'general',\n });\n \n return reply.send({\n success: result.success,\n data: result.result,\n error: result.error,\n });\n });\n}\n","import { CopilotClient, type SessionEvent } from '@github/copilot-sdk';\nimport type { Tool as CopilotTool } from '@github/copilot-sdk';\nimport { SessionService } from './session.service.js';\nimport { getAgentConfig, SESSION_TYPE_CONFIGS } from '@devmentorai/shared';\nimport type { SessionType, MessageContext } from '@devmentorai/shared';\nimport { devopsTools, getToolByName, type Tool } from '../tools/devops-tools.js';\n\ninterface CopilotSession {\n sessionId: string;\n session: Awaited<ReturnType<CopilotClient['createSession']>>;\n type: SessionType;\n}\n\n// MCP server configurations for different integrations\nconst MCP_SERVERS: Record<string, { type: 'http'; url: string; tools: string[] }> = {\n github: {\n type: 'http',\n url: 'https://api.githubcopilot.com/mcp/',\n tools: ['*'],\n },\n};\n\nexport class CopilotService {\n private client: CopilotClient | null = null;\n private sessions: Map<string, CopilotSession> = new Map();\n private initialized = false;\n private mockMode = false;\n\n constructor(private sessionService: SessionService) {}\n\n async initialize(): Promise<void> {\n try {\n this.client = new CopilotClient();\n await this.client.start();\n this.initialized = true;\n console.log('[CopilotService] Initialized successfully');\n } catch (error) {\n console.error('[CopilotService] Failed to initialize:', error);\n this.mockMode = true;\n this.initialized = true;\n console.warn('[CopilotService] Running in mock mode');\n }\n }\n\n isReady(): boolean {\n return this.initialized;\n }\n\n isMockMode(): boolean {\n return this.mockMode;\n }\n\n async createCopilotSession(\n sessionId: string,\n type: SessionType,\n model: string,\n systemPrompt?: string,\n enableMcp: boolean = false\n ): Promise<void> {\n if (this.mockMode || !this.client) {\n // Create mock session\n this.sessions.set(sessionId, {\n sessionId,\n session: null as any,\n type,\n });\n return;\n }\n\n const agentConfig = getAgentConfig(type);\n const typeConfig = SESSION_TYPE_CONFIGS[type];\n\n // Build SDK-compatible tools for DevOps sessions\n // The SDK calls tool.handler() directly and uses the return value as the result\n const tools = type === 'devops' ? this.buildSdkTools() : undefined;\n\n // Build MCP server config if enabled\n const mcpServers = enableMcp ? MCP_SERVERS : undefined;\n\n const session = await this.client.createSession({\n sessionId,\n model: model || typeConfig.defaultModel,\n streaming: true,\n customAgents: agentConfig ? [agentConfig] : undefined,\n systemMessage: systemPrompt ? { content: systemPrompt } : undefined,\n tools,\n mcpServers,\n });\n\n this.sessions.set(sessionId, { sessionId, session, type });\n }\n\n /**\n * Convert our Tool definitions to Copilot SDK Tool format.\n * The SDK expects tools with a `handler` function — it calls the handler\n * directly and uses the return value as the tool result (no sendToolResult needed).\n */\n private buildSdkTools(): CopilotTool<any>[] {\n return devopsTools.map((tool): CopilotTool<any> => ({\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters,\n handler: async (args: Record<string, unknown>) => {\n console.log(`[CopilotService] Executing tool ${tool.name}`);\n try {\n return await tool.handler(args);\n } catch (error) {\n console.error(`[CopilotService] Tool ${tool.name} failed:`, error);\n return `Error: ${error instanceof Error ? error.message : 'Unknown error'}`;\n }\n },\n }));\n }\n\n async resumeCopilotSession(sessionId: string): Promise<boolean> {\n if (this.mockMode || !this.client) {\n return true;\n }\n\n // First, try to resume existing session\n try {\n const session = await this.client.resumeSession(sessionId);\n // Try to get type from DB, fallback to 'general'\n const dbSession = this.sessionService.getSession(sessionId);\n this.sessions.set(sessionId, { sessionId, session, type: dbSession?.type || 'general' });\n console.log(`[CopilotService] Session ${sessionId} resumed from disk`);\n return true;\n } catch (resumeError) {\n console.log(`[CopilotService] Could not resume session ${sessionId}, will try to create new`);\n }\n\n // If resume fails, try to create a new session using DB info\n try {\n const dbSession = this.sessionService.getSession(sessionId);\n if (!dbSession) {\n console.error(`[CopilotService] Session ${sessionId} not found in database`);\n return false;\n }\n\n // Create new Copilot session with same parameters\n await this.createCopilotSession(\n sessionId,\n dbSession.type,\n dbSession.model,\n dbSession.systemPrompt || undefined,\n false // MCP disabled by default on recreate\n );\n console.log(`[CopilotService] Session ${sessionId} recreated successfully`);\n return true;\n } catch (createError) {\n console.error(`[CopilotService] Failed to create session ${sessionId}:`, createError);\n return false;\n }\n }\n\n async sendMessage(\n sessionId: string,\n prompt: string,\n context?: MessageContext,\n onEvent?: (event: SessionEvent) => void\n ): Promise<string> {\n return this.withRetry(async () => {\n const copilotSession = this.sessions.get(sessionId);\n \n // Note: The prompt should already be enriched with context by the route\n // We only add basic context fallback if the prompt doesn't contain it\n let fullPrompt = prompt;\n if (context?.selectedText && !prompt.includes(context.selectedText)) {\n fullPrompt = `Context (selected text):\\n${context.selectedText}\\n\\nUser request: ${prompt}`;\n }\n if (context?.pageUrl && !prompt.includes(context.pageUrl)) {\n fullPrompt = `Page: ${context.pageUrl}\\n${fullPrompt}`;\n }\n\n if (this.mockMode || !copilotSession?.session) {\n // Mock response\n return this.generateMockResponse(prompt, context);\n }\n\n let responseContent = '';\n\n // Set up event listener\n if (onEvent) {\n copilotSession.session.on(onEvent);\n }\n\n copilotSession.session.on((event: SessionEvent) => {\n if (event.type === 'assistant.message') {\n responseContent = event.data.content || '';\n }\n });\n\n // Send message - no systemMessage override to preserve Copilot's intelligence\n // The customAgents from session creation provide the persona/expertise\n const response = await copilotSession.session.sendAndWait({ prompt: fullPrompt });\n console.log(`[CopilotService] Received response for session ${sessionId}`);\n console.log(`[CopilotService] Response: ${response?.data}...`);\n console.log(`[CopilotService] responseContent: ${responseContent}...`);\n \n return response?.data.content || responseContent;\n }, 3, 1000);\n }\n\n async streamMessage(\n sessionId: string,\n prompt: string,\n context?: MessageContext,\n onEvent?: (event: SessionEvent) => void,\n attachments?: Array<{ type: 'file' | 'directory'; path: string; displayName?: string }>\n ): Promise<void> {\n let copilotSession = this.sessions.get(sessionId);\n\n // Auto-resume session if not in memory (e.g., after browser restart)\n if (!copilotSession?.session && !this.mockMode) {\n console.log(`[CopilotService] Session ${sessionId} not in memory, attempting auto-resume...`);\n const resumed = await this.resumeCopilotSession(sessionId);\n if (resumed) {\n copilotSession = this.sessions.get(sessionId);\n console.log(`[CopilotService] Session ${sessionId} auto-resumed successfully`);\n } else {\n console.warn(`[CopilotService] Failed to auto-resume session ${sessionId}, falling back to mock`);\n }\n }\n\n // Note: The prompt should already be enriched with context by the route\n // We only add basic context fallback if the prompt doesn't contain it\n let fullPrompt = prompt;\n if (context?.selectedText && !prompt.includes(context.selectedText)) {\n fullPrompt = `Context (selected text):\\n${context.selectedText}\\n\\nUser request: ${prompt}`;\n }\n\n if (this.mockMode || !copilotSession?.session) {\n // Mock streaming response\n console.log('[CopilotService] Streaming mock response');\n await this.streamMockResponse(prompt, context, onEvent);\n return;\n }\n\n console.log('[CopilotService] Starting real stream for session', sessionId);\n if (attachments && attachments.length > 0) {\n console.log(`[CopilotService] Sending ${attachments.length} attachments:`, attachments.map(a => a.path));\n }\n \n // Set up event listener\n if (onEvent) {\n copilotSession.session.on(onEvent);\n }\n\n // Send message with attachments if provided\n // The customAgents from session creation provide the persona/expertise\n copilotSession.session.send({ \n prompt: fullPrompt,\n attachments: attachments,\n });\n console.log('[CopilotService] Message sent, waiting for events...');\n }\n\n /**\n * Retry logic for transient errors\n */\n private async withRetry<T>(\n operation: () => Promise<T>,\n maxRetries: number = 3,\n delayMs: number = 1000\n ): Promise<T> {\n let lastError: Error | undefined;\n \n for (let attempt = 1; attempt <= maxRetries; attempt++) {\n try {\n return await operation();\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n \n // Don't retry on certain errors\n const nonRetryableErrors = ['authentication', 'invalid_session', 'rate_limit'];\n if (nonRetryableErrors.some(e => lastError!.message.toLowerCase().includes(e))) {\n throw lastError;\n }\n \n if (attempt < maxRetries) {\n console.warn(`[CopilotService] Attempt ${attempt} failed, retrying in ${delayMs}ms...`);\n await new Promise(resolve => setTimeout(resolve, delayMs));\n delayMs *= 2; // Exponential backoff\n }\n }\n }\n \n throw lastError;\n }\n\n /**\n * Get available tools for a session type\n */\n getAvailableTools(type: SessionType): Array<{ name: string; description: string }> {\n if (type === 'devops') {\n return devopsTools.map(t => ({ name: t.name, description: t.description }));\n }\n return [];\n }\n\n /**\n * Execute a tool directly (for testing or standalone use)\n */\n async executeTool(\n toolName: string, \n params: Record<string, unknown>\n ): Promise<{ success: boolean; result?: string; error?: string }> {\n const tool = getToolByName(toolName);\n if (!tool) {\n return { success: false, error: `Unknown tool: ${toolName}` };\n }\n \n try {\n const result = await tool.handler(params);\n return { success: true, result };\n } catch (error) {\n return { \n success: false, \n error: error instanceof Error ? error.message : String(error) \n };\n }\n }\n\n async abortRequest(sessionId: string): Promise<void> {\n const copilotSession = this.sessions.get(sessionId);\n if (copilotSession?.session && !this.mockMode) {\n await copilotSession.session.abort();\n }\n }\n\n async destroySession(sessionId: string): Promise<void> {\n const copilotSession = this.sessions.get(sessionId);\n \n if (copilotSession?.session && !this.mockMode) {\n try {\n // Abort any pending requests first\n await copilotSession.session.abort().catch(() => {});\n // Destroy the session (releases resources but doesn't delete files)\n await copilotSession.session.destroy();\n console.log(`[CopilotService] Session ${sessionId} destroyed successfully`);\n } catch (error) {\n console.error(`[CopilotService] Error destroying session ${sessionId}:`, error);\n // Continue with cleanup even if destroy fails\n }\n }\n \n // Delete session data from disk using SDK's deleteSession\n if (this.client && !this.mockMode) {\n try {\n await this.client.deleteSession(sessionId);\n console.log(`[CopilotService] Session ${sessionId} files deleted from disk`);\n } catch (error) {\n // Session might not exist on disk, that's OK\n console.log(`[CopilotService] Could not delete session files (may not exist): ${sessionId}`);\n }\n }\n \n // Remove from in-memory map\n this.sessions.delete(sessionId);\n console.log(`[CopilotService] Session ${sessionId} removed from memory`);\n }\n\n async shutdown(): Promise<void> {\n // Destroy all sessions\n for (const [sessionId, copilotSession] of this.sessions) {\n try {\n if (copilotSession.session && !this.mockMode) {\n await copilotSession.session.destroy();\n }\n } catch (error) {\n console.error(`[CopilotService] Failed to destroy session ${sessionId}:`, error);\n }\n }\n this.sessions.clear();\n\n // Stop client\n if (this.client && !this.mockMode) {\n try {\n await this.client.stop();\n } catch (error) {\n console.error('[CopilotService] Failed to stop client:', error);\n }\n }\n\n this.initialized = false;\n }\n\n // Mock implementations for development without Copilot CLI\n private generateMockResponse(prompt: string, context?: MessageContext): string {\n const action = context?.action;\n \n if (action === 'explain') {\n return `**Explanation:**\\n\\nThis appears to be ${context?.selectedText?.slice(0, 50)}...\\n\\nIn essence, this code/text demonstrates a common pattern used in software development. The key points are:\\n\\n1. It handles a specific use case\\n2. It follows best practices\\n3. It can be extended for additional functionality`;\n }\n \n if (action === 'translate') {\n return `**Translation:**\\n\\n${context?.selectedText || 'No text provided'}`;\n }\n \n if (action === 'rewrite') {\n return `**Rewritten:**\\n\\n${context?.selectedText || prompt}`;\n }\n \n if (action === 'fix_grammar') {\n return `**Corrected:**\\n\\n${context?.selectedText || prompt}`;\n }\n\n return `**Mock Response:**\\n\\nI understand you're asking about: \"${prompt.slice(0, 100)}...\"\\n\\nThis is a mock response because the Copilot SDK is not available. In production, you would receive intelligent responses powered by GitHub Copilot.\\n\\nTo enable real responses:\\n1. Install GitHub Copilot CLI\\n2. Authenticate with your GitHub account\\n3. Restart the DevMentorAI backend`;\n }\n\n private async streamMockResponse(\n prompt: string,\n context?: MessageContext,\n onEvent?: (event: SessionEvent) => void\n ): Promise<void> {\n const response = this.generateMockResponse(prompt, context);\n const words = response.split(' ');\n\n // Simulate streaming with delays\n for (let i = 0; i < words.length; i++) {\n await new Promise(resolve => setTimeout(resolve, 50));\n \n onEvent?.({\n type: 'assistant.message_delta',\n data: { deltaContent: words[i] + (i < words.length - 1 ? ' ' : '') },\n } as SessionEvent);\n }\n\n onEvent?.({\n type: 'assistant.message',\n data: { content: response },\n } as SessionEvent);\n\n onEvent?.({\n type: 'session.idle',\n data: {},\n } as SessionEvent);\n }\n}\n","/**\n * Custom DevOps Analysis Tools for DevMentorAI\n * \n * These tools extend Copilot's capabilities with specialized DevOps functionality:\n * - Configuration file analysis\n * - Infrastructure best practices checking\n * - Log analysis\n * - Cost estimation helpers\n */\n\nimport * as fs from 'fs/promises';\nimport * as path from 'path';\n\nexport interface Tool {\n name: string;\n description: string;\n parameters: {\n type: 'object';\n properties: Record<string, {\n type: string;\n description: string;\n enum?: string[];\n }>;\n required: string[];\n };\n handler: (params: Record<string, unknown>) => Promise<string>;\n}\n\n// Allowed directories for file access (security sandbox)\nconst ALLOWED_DIRECTORIES = [\n process.env.HOME || '/home',\n '/tmp',\n];\n\nfunction isPathAllowed(filePath: string): boolean {\n const resolved = path.resolve(filePath);\n return ALLOWED_DIRECTORIES.some(dir => resolved.startsWith(dir));\n}\n\n/**\n * Read file contents with security checks\n */\nexport const readFileTool: Tool = {\n name: 'read_file',\n description: 'Read the contents of a local file. Use this to analyze configuration files, logs, or code.',\n parameters: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Absolute or relative path to the file to read',\n },\n maxLines: {\n type: 'number',\n description: 'Maximum number of lines to read (default: 500)',\n },\n },\n required: ['path'],\n },\n handler: async (params) => {\n const filePath = params.path as string;\n const maxLines = (params.maxLines as number) || 500;\n\n if (!isPathAllowed(filePath)) {\n return `Error: Access denied. Path \"${filePath}\" is outside allowed directories.`;\n }\n\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const lines = content.split('\\n');\n \n if (lines.length > maxLines) {\n return lines.slice(0, maxLines).join('\\n') + \n `\\n\\n[Truncated: ${lines.length - maxLines} more lines]`;\n }\n \n return content;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') {\n return `Error: File not found: ${filePath}`;\n }\n return `Error reading file: ${error}`;\n }\n },\n};\n\n/**\n * List directory contents\n */\nexport const listDirectoryTool: Tool = {\n name: 'list_directory',\n description: 'List contents of a directory. Useful for exploring project structure.',\n parameters: {\n type: 'object',\n properties: {\n path: {\n type: 'string',\n description: 'Path to the directory to list',\n },\n recursive: {\n type: 'boolean',\n description: 'Whether to list recursively (default: false, max depth: 3)',\n },\n },\n required: ['path'],\n },\n handler: async (params) => {\n const dirPath = params.path as string;\n const recursive = params.recursive as boolean || false;\n\n if (!isPathAllowed(dirPath)) {\n return `Error: Access denied. Path \"${dirPath}\" is outside allowed directories.`;\n }\n\n async function listDir(dir: string, depth: number = 0): Promise<string[]> {\n if (depth > 3) return [];\n \n const entries = await fs.readdir(dir, { withFileTypes: true });\n const results: string[] = [];\n \n for (const entry of entries) {\n const prefix = ' '.repeat(depth);\n const fullPath = path.join(dir, entry.name);\n \n if (entry.isDirectory()) {\n results.push(`${prefix}📁 ${entry.name}/`);\n if (recursive) {\n results.push(...await listDir(fullPath, depth + 1));\n }\n } else {\n const stats = await fs.stat(fullPath);\n const size = formatSize(stats.size);\n results.push(`${prefix}📄 ${entry.name} (${size})`);\n }\n }\n \n return results;\n }\n\n try {\n const contents = await listDir(dirPath);\n return contents.join('\\n');\n } catch (error) {\n return `Error listing directory: ${error}`;\n }\n },\n};\n\nfunction formatSize(bytes: number): string {\n const units = ['B', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unitIndex = 0;\n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n return `${size.toFixed(1)} ${units[unitIndex]}`;\n}\n\n/**\n * Analyze configuration file for best practices\n */\nexport const analyzeConfigTool: Tool = {\n name: 'analyze_config',\n description: 'Analyze a configuration file for DevOps best practices. Supports Kubernetes, Docker, Terraform, and CloudFormation.',\n parameters: {\n type: 'object',\n properties: {\n content: {\n type: 'string',\n description: 'The configuration file content to analyze',\n },\n type: {\n type: 'string',\n enum: ['kubernetes', 'docker', 'terraform', 'cloudformation', 'github-actions', 'auto'],\n description: 'Type of configuration (auto-detect if not specified)',\n },\n },\n required: ['content'],\n },\n handler: async (params) => {\n const content = params.content as string;\n let configType = params.type as string || 'auto';\n\n // Auto-detect config type\n if (configType === 'auto') {\n configType = detectConfigType(content);\n }\n\n const issues: string[] = [];\n const suggestions: string[] = [];\n\n switch (configType) {\n case 'kubernetes':\n analyzeKubernetes(content, issues, suggestions);\n break;\n case 'docker':\n analyzeDocker(content, issues, suggestions);\n break;\n case 'terraform':\n analyzeTerraform(content, issues, suggestions);\n break;\n case 'cloudformation':\n analyzeCloudFormation(content, issues, suggestions);\n break;\n case 'github-actions':\n analyzeGitHubActions(content, issues, suggestions);\n break;\n default:\n return `Could not determine configuration type. Please specify the type parameter.`;\n }\n\n let result = `## Configuration Analysis (${configType})\\n\\n`;\n \n if (issues.length > 0) {\n result += `### ⚠️ Issues Found\\n`;\n issues.forEach((issue, i) => {\n result += `${i + 1}. ${issue}\\n`;\n });\n result += '\\n';\n } else {\n result += `### ✅ No Critical Issues Found\\n\\n`;\n }\n\n if (suggestions.length > 0) {\n result += `### 💡 Suggestions\\n`;\n suggestions.forEach((suggestion, i) => {\n result += `${i + 1}. ${suggestion}\\n`;\n });\n }\n\n return result;\n },\n};\n\nfunction detectConfigType(content: string): string {\n if (content.includes('apiVersion:') && content.includes('kind:')) return 'kubernetes';\n if (content.includes('FROM ') || content.includes('COPY ') || content.includes('RUN ')) return 'docker';\n if (content.includes('resource \"') || content.includes('provider \"')) return 'terraform';\n if (content.includes('AWSTemplateFormatVersion') || content.includes('Resources:')) return 'cloudformation';\n if (content.includes('jobs:') && content.includes('runs-on:')) return 'github-actions';\n return 'unknown';\n}\n\nfunction analyzeKubernetes(content: string, issues: string[], suggestions: string[]): void {\n // Resource limits\n if (!content.includes('resources:') || !content.includes('limits:')) {\n issues.push('Missing resource limits. Pods without limits can consume excessive cluster resources.');\n }\n \n // Security context\n if (!content.includes('securityContext:')) {\n suggestions.push('Consider adding securityContext to restrict container privileges.');\n }\n \n // Image tag\n if (content.includes(':latest')) {\n issues.push('Using :latest tag. Pin specific image versions for reproducible deployments.');\n }\n \n // Probes\n if (!content.includes('livenessProbe:') && !content.includes('readinessProbe:')) {\n suggestions.push('Add health probes (livenessProbe/readinessProbe) for better reliability.');\n }\n \n // Namespace\n if (!content.includes('namespace:')) {\n suggestions.push('Explicitly specify namespace to avoid deploying to default namespace.');\n }\n\n // Run as non-root\n if (content.includes('runAsRoot: true') || content.includes('privileged: true')) {\n issues.push('Container configured to run as root or privileged. This is a security risk.');\n }\n}\n\nfunction analyzeDocker(content: string, issues: string[], suggestions: string[]): void {\n const lines = content.split('\\n');\n \n // Base image\n const fromLine = lines.find(l => l.trim().startsWith('FROM '));\n if (fromLine?.includes(':latest')) {\n issues.push('Using :latest base image. Pin a specific version for reproducible builds.');\n }\n \n // Multiple RUN commands\n const runCount = lines.filter(l => l.trim().startsWith('RUN ')).length;\n if (runCount > 5) {\n suggestions.push(`${runCount} separate RUN commands. Consider combining them to reduce image layers.`);\n }\n \n // COPY vs ADD\n if (content.includes('ADD ') && !content.includes('.tar') && !content.includes('http')) {\n suggestions.push('Use COPY instead of ADD for simple file copying. ADD has extra features that may be unnecessary.');\n }\n \n // .dockerignore reminder\n if (content.includes('COPY . ') || content.includes('COPY ./ ')) {\n suggestions.push('Copying entire context. Ensure .dockerignore is configured to exclude unnecessary files.');\n }\n \n // Non-root user\n if (!content.includes('USER ')) {\n suggestions.push('No USER directive. Consider running as non-root user for security.');\n }\n \n // Multi-stage builds\n if (!content.includes('AS ') && content.includes('npm install') || content.includes('go build')) {\n suggestions.push('Consider multi-stage builds to reduce final image size.');\n }\n}\n\nfunction analyzeTerraform(content: string, issues: string[], suggestions: string[]): void {\n // Version constraints\n if (!content.includes('required_version') && !content.includes('required_providers')) {\n issues.push('Missing version constraints. Pin Terraform and provider versions for reproducibility.');\n }\n \n // Hardcoded values\n const hardcodedPatterns = [\n /ami-[a-z0-9]+/,\n /subnet-[a-z0-9]+/,\n /sg-[a-z0-9]+/,\n /vpc-[a-z0-9]+/,\n ];\n for (const pattern of hardcodedPatterns) {\n if (pattern.test(content)) {\n suggestions.push('Hardcoded AWS resource IDs detected. Consider using data sources or variables.');\n break;\n }\n }\n \n // State backend\n if (!content.includes('backend \"')) {\n suggestions.push('No remote backend configured. Use S3/GCS/Azure for team collaboration.');\n }\n \n // Sensitive variables\n if (content.includes('password') || content.includes('secret') || content.includes('api_key')) {\n if (!content.includes('sensitive = true')) {\n issues.push('Potentially sensitive variables without sensitive = true flag.');\n }\n }\n \n // Encryption\n if (content.includes('aws_s3_bucket') && !content.includes('server_side_encryption')) {\n suggestions.push('S3 bucket without explicit encryption configuration.');\n }\n}\n\nfunction analyzeCloudFormation(content: string, issues: string[], suggestions: string[]): void {\n // DeletionPolicy\n if (content.includes('AWS::RDS::') || content.includes('AWS::S3::Bucket')) {\n if (!content.includes('DeletionPolicy')) {\n issues.push('Stateful resources without DeletionPolicy. Data may be lost on stack deletion.');\n }\n }\n \n // UpdateReplacePolicy\n if (!content.includes('UpdateReplacePolicy')) {\n suggestions.push('Consider adding UpdateReplacePolicy for stateful resources.');\n }\n \n // Stack drift detection hint\n suggestions.push('Run `aws cloudformation detect-stack-drift` regularly to catch manual changes.');\n \n // Parameters without constraints\n if (content.includes('Parameters:') && !content.includes('AllowedValues')) {\n suggestions.push('Consider adding AllowedValues constraints to parameters.');\n }\n}\n\nfunction analyzeGitHubActions(content: string, issues: string[], suggestions: string[]): void {\n // Pinned actions\n if (content.includes('uses: ') && !content.includes('@v') && !content.includes('@sha')) {\n issues.push('Actions without version pinning. Pin to specific versions or SHA for security.');\n }\n \n // Secrets in env\n if (content.includes('${{ secrets.') && content.includes('echo ')) {\n issues.push('Potential secret exposure in echo/print commands.');\n }\n \n // Permissions\n if (!content.includes('permissions:')) {\n suggestions.push('Explicitly define job permissions for better security (least privilege).');\n }\n \n // Caching\n if ((content.includes('npm ') || content.includes('pip ') || content.includes('go ')) && \n !content.includes('actions/cache')) {\n suggestions.push('Consider adding caching to speed up workflows.');\n }\n \n // Timeout\n if (!content.includes('timeout-minutes:')) {\n suggestions.push('Add timeout-minutes to prevent stuck workflows from running indefinitely.');\n }\n}\n\n/**\n * Analyze error logs\n */\nexport const analyzeErrorTool: Tool = {\n name: 'analyze_error',\n description: 'Analyze error messages or logs to diagnose issues and suggest solutions.',\n parameters: {\n type: 'object',\n properties: {\n error: {\n type: 'string',\n description: 'The error message or log content to analyze',\n },\n context: {\n type: 'string',\n enum: ['kubernetes', 'docker', 'terraform', 'aws', 'linux', 'nodejs', 'python', 'general'],\n description: 'Context/environment where the error occurred',\n },\n },\n required: ['error'],\n },\n handler: async (params) => {\n const error = params.error as string;\n const context = params.context as string || 'general';\n\n const analysis: string[] = [];\n const possibleCauses: string[] = [];\n const solutions: string[] = [];\n\n // Common patterns\n if (error.includes('permission denied') || error.includes('EACCES')) {\n possibleCauses.push('Insufficient file system permissions');\n solutions.push('Check file/directory permissions with `ls -la`');\n solutions.push('Try running with appropriate user or `sudo` if necessary');\n }\n\n if (error.includes('connection refused') || error.includes('ECONNREFUSED')) {\n possibleCauses.push('Target service is not running or not listening on expected port');\n solutions.push('Verify the service is running: `systemctl status <service>`');\n solutions.push('Check if the port is open: `netstat -tlnp | grep <port>`');\n }\n\n if (error.includes('out of memory') || error.includes('OOMKilled')) {\n possibleCauses.push('Application exceeded memory limits');\n solutions.push('Increase memory limits if possible');\n solutions.push('Profile memory usage to find leaks');\n solutions.push('Consider horizontal scaling');\n }\n\n if (error.includes('timeout') || error.includes('ETIMEDOUT')) {\n possibleCauses.push('Network latency or unreachable endpoint');\n possibleCauses.push('Slow database queries or API responses');\n solutions.push('Check network connectivity: `ping`, `traceroute`');\n solutions.push('Review and optimize slow queries');\n solutions.push('Consider increasing timeout values');\n }\n\n // Context-specific patterns\n if (context === 'kubernetes') {\n if (error.includes('CrashLoopBackOff')) {\n possibleCauses.push('Container fails to start or crashes immediately');\n solutions.push('Check container logs: `kubectl logs <pod> --previous`');\n solutions.push('Verify image exists and is pullable');\n solutions.push('Check resource limits and requests');\n }\n if (error.includes('ImagePullBackOff')) {\n possibleCauses.push('Cannot pull container image');\n solutions.push('Verify image name and tag');\n solutions.push('Check image registry credentials (imagePullSecrets)');\n }\n }\n\n if (context === 'docker') {\n if (error.includes('no space left on device')) {\n possibleCauses.push('Docker disk space exhausted');\n solutions.push('Clean up: `docker system prune -a`');\n solutions.push('Remove unused images: `docker image prune`');\n }\n }\n\n if (possibleCauses.length === 0) {\n analysis.push('No specific pattern matched. Consider:');\n analysis.push('- Searching the error message in documentation');\n analysis.push('- Checking application logs for more context');\n analysis.push('- Verifying configuration and environment variables');\n }\n\n let result = `## Error Analysis\\n\\n`;\n result += `**Context:** ${context}\\n\\n`;\n \n if (possibleCauses.length > 0) {\n result += `### Possible Causes\\n`;\n possibleCauses.forEach(cause => result += `- ${cause}\\n`);\n result += '\\n';\n }\n \n if (solutions.length > 0) {\n result += `### Suggested Solutions\\n`;\n solutions.forEach((solution, i) => result += `${i + 1}. ${solution}\\n`);\n result += '\\n';\n }\n \n if (analysis.length > 0) {\n result += `### Notes\\n`;\n analysis.forEach(note => result += `${note}\\n`);\n }\n\n return result;\n },\n};\n\n/**\n * Export all DevOps tools\n */\nexport const devopsTools: Tool[] = [\n readFileTool,\n listDirectoryTool,\n analyzeConfigTool,\n analyzeErrorTool,\n];\n\nexport function getToolByName(name: string): Tool | undefined {\n return devopsTools.find(tool => tool.name === name);\n}\n","import type { Database } from 'better-sqlite3';\nimport {\n generateSessionId,\n generateMessageId,\n formatDate,\n getAgentConfig,\n getDefaultModel,\n} from '@devmentorai/shared';\nimport type {\n Session,\n SessionType,\n SessionStatus,\n CreateSessionRequest,\n UpdateSessionRequest,\n Message,\n MessageMetadata,\n PaginatedResponse,\n} from '@devmentorai/shared';\n\ninterface DbSession {\n id: string;\n name: string;\n type: SessionType;\n status: SessionStatus;\n model: string;\n system_prompt: string | null;\n custom_agent: string | null;\n message_count: number;\n created_at: string;\n updated_at: string;\n}\n\ninterface DbMessage {\n id: string;\n session_id: string;\n role: 'user' | 'assistant' | 'system';\n content: string;\n timestamp: string;\n metadata: string | null;\n}\n\nexport class SessionService {\n constructor(private db: Database) {}\n\n // Sessions\n listSessions(page = 1, pageSize = 50): PaginatedResponse<Session> {\n const offset = (page - 1) * pageSize;\n \n const countStmt = this.db.prepare('SELECT COUNT(*) as count FROM sessions');\n const count = (countStmt.get() as { count: number }).count;\n\n const stmt = this.db.prepare(`\n SELECT * FROM sessions \n ORDER BY updated_at DESC \n LIMIT ? OFFSET ?\n `);\n const rows = stmt.all(pageSize, offset) as DbSession[];\n\n return {\n items: rows.map(this.mapDbSession),\n total: count,\n page,\n pageSize,\n hasMore: offset + rows.length < count,\n };\n }\n\n getSession(id: string): Session | null {\n const stmt = this.db.prepare('SELECT * FROM sessions WHERE id = ?');\n const row = stmt.get(id) as DbSession | undefined;\n return row ? this.mapDbSession(row) : null;\n }\n\n createSession(request: CreateSessionRequest): Session {\n const id = generateSessionId();\n const now = formatDate();\n const agentConfig = getAgentConfig(request.type);\n const model = request.model || getDefaultModel(request.type);\n \n const stmt = this.db.prepare(`\n INSERT INTO sessions (id, name, type, model, system_prompt, custom_agent, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n \n stmt.run(\n id,\n request.name,\n request.type,\n model,\n request.systemPrompt || agentConfig?.prompt || null,\n agentConfig?.name || null,\n now,\n now\n );\n\n return this.getSession(id)!;\n }\n\n updateSession(id: string, request: UpdateSessionRequest): Session | null {\n const session = this.getSession(id);\n if (!session) return null;\n\n const updates: string[] = [];\n const values: (string | number)[] = [];\n\n if (request.name !== undefined) {\n updates.push('name = ?');\n values.push(request.name);\n }\n if (request.status !== undefined) {\n updates.push('status = ?');\n values.push(request.status);\n }\n\n if (updates.length === 0) return session;\n\n updates.push('updated_at = ?');\n values.push(formatDate());\n values.push(id);\n\n const stmt = this.db.prepare(`\n UPDATE sessions SET ${updates.join(', ')} WHERE id = ?\n `);\n stmt.run(...values);\n\n return this.getSession(id);\n }\n\n deleteSession(id: string): boolean {\n const stmt = this.db.prepare('DELETE FROM sessions WHERE id = ?');\n const result = stmt.run(id);\n return result.changes > 0;\n }\n\n incrementMessageCount(sessionId: string): void {\n const stmt = this.db.prepare(`\n UPDATE sessions \n SET message_count = message_count + 1, updated_at = ?\n WHERE id = ?\n `);\n stmt.run(formatDate(), sessionId);\n }\n\n // Messages\n listMessages(sessionId: string, page = 1, pageSize = 100): PaginatedResponse<Message> {\n const offset = (page - 1) * pageSize;\n\n const countStmt = this.db.prepare('SELECT COUNT(*) as count FROM messages WHERE session_id = ?');\n const count = (countStmt.get(sessionId) as { count: number }).count;\n\n const stmt = this.db.prepare(`\n SELECT * FROM messages \n WHERE session_id = ?\n ORDER BY timestamp ASC\n LIMIT ? OFFSET ?\n `);\n const rows = stmt.all(sessionId, pageSize, offset) as DbMessage[];\n\n return {\n items: rows.map(row => this.mapDbMessage(row)),\n total: count,\n page,\n pageSize,\n hasMore: offset + rows.length < count,\n };\n }\n\n addMessage(\n sessionId: string,\n role: 'user' | 'assistant' | 'system',\n content: string,\n metadata?: MessageMetadata\n ): Message {\n const id = generateMessageId();\n const timestamp = formatDate();\n\n const stmt = this.db.prepare(`\n INSERT INTO messages (id, session_id, role, content, timestamp, metadata)\n VALUES (?, ?, ?, ?, ?, ?)\n `);\n \n stmt.run(\n id,\n sessionId,\n role,\n content,\n timestamp,\n metadata ? JSON.stringify(metadata) : null\n );\n\n this.incrementMessageCount(sessionId);\n\n return {\n id,\n sessionId,\n role,\n content,\n timestamp,\n metadata,\n };\n }\n\n updateMessageContent(messageId: string, content: string): void {\n const stmt = this.db.prepare('UPDATE messages SET content = ? WHERE id = ?');\n stmt.run(content, messageId);\n }\n\n updateMessageMetadata(messageId: string, metadata: Record<string, unknown>): void {\n const stmt = this.db.prepare('UPDATE messages SET metadata = ? WHERE id = ?');\n stmt.run(JSON.stringify(metadata), messageId);\n }\n\n // ============================================================================\n // Context Persistence (Phase 5)\n // ============================================================================\n\n /**\n * Save context for a session (associated with a message)\n */\n saveContext(\n sessionId: string,\n contextJson: string,\n messageId?: string,\n pageUrl?: string,\n pageTitle?: string,\n platform?: string\n ): string {\n const id = `ctx_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n const now = formatDate();\n\n const stmt = this.db.prepare(`\n INSERT INTO session_contexts (id, session_id, message_id, context_json, page_url, page_title, platform, extracted_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n stmt.run(id, sessionId, messageId || null, contextJson, pageUrl || null, pageTitle || null, platform || null, now);\n\n return id;\n }\n\n /**\n * Get the most recent context for a session\n */\n getLatestContext(sessionId: string): { id: string; contextJson: string; pageUrl?: string; platform?: string; extractedAt: string } | null {\n const stmt = this.db.prepare(`\n SELECT id, context_json, page_url, platform, extracted_at\n FROM session_contexts\n WHERE session_id = ?\n ORDER BY extracted_at DESC\n LIMIT 1\n `);\n\n const row = stmt.get(sessionId) as { id: string; context_json: string; page_url: string | null; platform: string | null; extracted_at: string } | undefined;\n\n if (!row) return null;\n\n return {\n id: row.id,\n contextJson: row.context_json,\n pageUrl: row.page_url || undefined,\n platform: row.platform || undefined,\n extractedAt: row.extracted_at,\n };\n }\n\n /**\n * Get context history for a session\n */\n getContextHistory(sessionId: string, limit: number = 10): Array<{\n id: string;\n messageId?: string;\n pageUrl?: string;\n pageTitle?: string;\n platform?: string;\n extractedAt: string;\n }> {\n const stmt = this.db.prepare(`\n SELECT id, message_id, page_url, page_title, platform, extracted_at\n FROM session_contexts\n WHERE session_id = ?\n ORDER BY extracted_at DESC\n LIMIT ?\n `);\n\n const rows = stmt.all(sessionId, limit) as Array<{\n id: string;\n message_id: string | null;\n page_url: string | null;\n page_title: string | null;\n platform: string | null;\n extracted_at: string;\n }>;\n\n return rows.map(row => ({\n id: row.id,\n messageId: row.message_id || undefined,\n pageUrl: row.page_url || undefined,\n pageTitle: row.page_title || undefined,\n platform: row.platform || undefined,\n extractedAt: row.extracted_at,\n }));\n }\n\n /**\n * Get a specific context by ID\n */\n getContext(contextId: string): { id: string; sessionId: string; contextJson: string; extractedAt: string } | null {\n const stmt = this.db.prepare(`\n SELECT id, session_id, context_json, extracted_at\n FROM session_contexts\n WHERE id = ?\n `);\n\n const row = stmt.get(contextId) as { id: string; session_id: string; context_json: string; extracted_at: string } | undefined;\n\n if (!row) return null;\n\n return {\n id: row.id,\n sessionId: row.session_id,\n contextJson: row.context_json,\n extractedAt: row.extracted_at,\n };\n }\n\n /**\n * Clean up old contexts for a session (keep only last N)\n */\n cleanupOldContexts(sessionId: string, keepCount: number = 20): number {\n // Get IDs to keep\n const keepStmt = this.db.prepare(`\n SELECT id FROM session_contexts\n WHERE session_id = ?\n ORDER BY extracted_at DESC\n LIMIT ?\n `);\n const idsToKeep = (keepStmt.all(sessionId, keepCount) as Array<{ id: string }>).map(r => r.id);\n\n if (idsToKeep.length === 0) return 0;\n\n // Delete older contexts\n const deleteStmt = this.db.prepare(`\n DELETE FROM session_contexts\n WHERE session_id = ?\n AND id NOT IN (${idsToKeep.map(() => '?').join(',')})\n `);\n\n const result = deleteStmt.run(sessionId, ...idsToKeep);\n return result.changes;\n }\n\n /**\n * Get context count for a session\n */\n getContextCount(sessionId: string): number {\n const stmt = this.db.prepare('SELECT COUNT(*) as count FROM session_contexts WHERE session_id = ?');\n const result = stmt.get(sessionId) as { count: number };\n return result.count;\n }\n\n private mapDbSession(row: DbSession): Session {\n return {\n id: row.id,\n name: row.name,\n type: row.type,\n status: row.status,\n model: row.model,\n systemPrompt: row.system_prompt || undefined,\n customAgent: row.custom_agent || undefined,\n messageCount: row.message_count,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n };\n }\n\n private mapDbMessage(row: DbMessage): Message {\n let metadata = row.metadata ? JSON.parse(row.metadata) : undefined;\n \n // Fix legacy image URLs that have incorrect format\n if (metadata?.images) {\n metadata.images = metadata.images.map((img: Record<string, unknown>) => ({\n ...img,\n thumbnailUrl: this.fixImageUrl(img.thumbnailUrl as string | undefined),\n fullImageUrl: this.fixImageUrl(img.fullImageUrl as string | undefined),\n }));\n }\n \n return {\n id: row.id,\n sessionId: row.session_id,\n role: row.role,\n content: row.content,\n timestamp: row.timestamp,\n metadata,\n };\n }\n\n /**\n * Fix legacy image URLs that have incorrect format\n * - Adds missing port (localhost -> localhost:3847)\n * - Removes duplicate \"images/images/\" path\n */\n private fixImageUrl(url: string | undefined): string | undefined {\n if (!url) return url;\n \n let fixed = url;\n \n // Fix missing port: http://localhost/api -> http://localhost:3847/api\n if (fixed.includes('http://localhost/api')) {\n fixed = fixed.replace('http://localhost/api', 'http://localhost:3847/api');\n }\n \n // Fix duplicate images path: /api/images/images/ -> /api/images/\n if (fixed.includes('/api/images/images/')) {\n fixed = fixed.replace('/api/images/images/', '/api/images/');\n }\n \n return fixed;\n }\n}\n","import Database from 'better-sqlite3';\nimport path from 'path';\nimport os from 'os';\nimport fs from 'fs';\n\nconst DB_DIR = path.join(os.homedir(), '.devmentorai');\nconst DB_PATH = path.join(DB_DIR, 'devmentorai.db');\n\nconsole.log(`Database path: ${DB_PATH}`);\n\nexport function initDatabase(): Database.Database {\n // Ensure directory exists\n if (!fs.existsSync(DB_DIR)) {\n fs.mkdirSync(DB_DIR, { recursive: true });\n }\n\n const db = new Database(DB_PATH);\n \n // Enable WAL mode for better performance\n db.pragma('journal_mode = WAL');\n \n // Create tables\n db.exec(`\n CREATE TABLE IF NOT EXISTS sessions (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n type TEXT NOT NULL CHECK (type IN ('devops', 'writing', 'development', 'general')),\n status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'paused', 'closed')),\n model TEXT NOT NULL DEFAULT 'gpt-4.1',\n system_prompt TEXT,\n custom_agent TEXT,\n message_count INTEGER NOT NULL DEFAULT 0,\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n updated_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS messages (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n role TEXT NOT NULL CHECK (role IN ('user', 'assistant', 'system')),\n content TEXT NOT NULL,\n timestamp TEXT NOT NULL DEFAULT (datetime('now')),\n metadata TEXT,\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE\n );\n\n -- New table for session context persistence (Phase 5)\n CREATE TABLE IF NOT EXISTS session_contexts (\n id TEXT PRIMARY KEY,\n session_id TEXT NOT NULL,\n message_id TEXT,\n context_json TEXT NOT NULL,\n page_url TEXT,\n page_title TEXT,\n platform TEXT,\n extracted_at TEXT NOT NULL DEFAULT (datetime('now')),\n FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE,\n FOREIGN KEY (message_id) REFERENCES messages(id) ON DELETE SET NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_messages_session_id ON messages(session_id);\n CREATE INDEX IF NOT EXISTS idx_messages_timestamp ON messages(timestamp);\n CREATE INDEX IF NOT EXISTS idx_session_contexts_session_id ON session_contexts(session_id);\n CREATE INDEX IF NOT EXISTS idx_session_contexts_extracted_at ON session_contexts(extracted_at);\n `);\n\n return db;\n}\n\nexport type { Database };\n"],"mappings":"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","names":["z","z","userPrompt","resolve","fs","path","path","fs","fs","path","resolve","path","fs"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "devmentorai-server",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "DevMentorAI backend server — AI-powered DevOps mentoring via GitHub Copilot. Run with: npx devmentorai-server",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"main": "./dist/server.js",
|
|
9
|
+
"bin": {
|
|
10
|
+
"devmentorai-server": "./dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"keywords": [
|
|
18
|
+
"devmentorai",
|
|
19
|
+
"copilot",
|
|
20
|
+
"github-copilot",
|
|
21
|
+
"devops",
|
|
22
|
+
"ai",
|
|
23
|
+
"cli",
|
|
24
|
+
"mentoring"
|
|
25
|
+
],
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/BOTOOM/devmentorai.git",
|
|
29
|
+
"directory": "apps/backend"
|
|
30
|
+
},
|
|
31
|
+
"homepage": "https://github.com/BOTOOM/devmentorai#readme",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/BOTOOM/devmentorai/issues"
|
|
34
|
+
},
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=20.0.0"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"dev": "tsx watch src/server.ts",
|
|
40
|
+
"build": "tsup",
|
|
41
|
+
"start": "node dist/server.js",
|
|
42
|
+
"start:cli": "node dist/cli.js",
|
|
43
|
+
"test": "vitest",
|
|
44
|
+
"test:coverage": "vitest --coverage",
|
|
45
|
+
"typecheck": "tsc --noEmit",
|
|
46
|
+
"lint": "eslint src/",
|
|
47
|
+
"clean": "rm -rf dist",
|
|
48
|
+
"prepublishOnly": "pnpm run build",
|
|
49
|
+
"release": "semantic-release"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@fastify/cors": "^10.0.2",
|
|
53
|
+
"@github/copilot-sdk": "^0.1.0",
|
|
54
|
+
"better-sqlite3": "^11.7.0",
|
|
55
|
+
"drizzle-orm": "^0.38.4",
|
|
56
|
+
"fastify": "^5.2.1",
|
|
57
|
+
"pino": "^9.6.0",
|
|
58
|
+
"pino-pretty": "^13.0.0",
|
|
59
|
+
"sharp": "^0.34.5",
|
|
60
|
+
"zod": "^3.24.1"
|
|
61
|
+
},
|
|
62
|
+
"devDependencies": {
|
|
63
|
+
"@devmentorai/shared": "workspace:*",
|
|
64
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
65
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
66
|
+
"@semantic-release/git": "^10.0.1",
|
|
67
|
+
"@semantic-release/github": "^12.0.5",
|
|
68
|
+
"@semantic-release/npm": "^13.1.4",
|
|
69
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
70
|
+
"@types/better-sqlite3": "^7.6.12",
|
|
71
|
+
"@types/node": "^22.10.5",
|
|
72
|
+
"@types/sharp": "^0.32.0",
|
|
73
|
+
"conventional-changelog-conventionalcommits": "^9.1.0",
|
|
74
|
+
"drizzle-kit": "^0.30.2",
|
|
75
|
+
"semantic-release": "^25.0.3",
|
|
76
|
+
"tsup": "^8.5.1",
|
|
77
|
+
"tsx": "^4.19.2",
|
|
78
|
+
"typescript": "^5.7.3",
|
|
79
|
+
"vitest": "^2.1.8"
|
|
80
|
+
}
|
|
81
|
+
}
|