126 lines · 3.7 KB · TypeScript
RawDownload
/** * HTTP route handlers for Utility Operations. * * Routes: * - GET /api/version - App version * - POST /api/read-claude-md - Read CLAUDE.md files * - POST /api/read-directory-claude-md - Read directory CLAUDE.md * - POST /api/read-mentioned-file - Read mentioned file * - POST /api/open-path - No-op in browser * - POST /api/open-external - No-op in browser */ import { createLogger } from '@shared/utils/logger';import * as fs from 'fs';import * as path from 'path'; import { type ClaudeMdFileInfo, readAllClaudeMdFiles, readDirectoryClaudeMd } from '../services';import { validateFilePath } from '../utils/pathValidation';import { countTokens } from '../utils/tokenizer'; import type { FastifyInstance } from 'fastify'; const logger = createLogger('HTTP:utility'); export function registerUtilityRoutes(app: FastifyInstance): void {  // App version  app.get('/api/version', async () => {    try {      // Read version from package.json (works in both Electron and Node)      const pkgPath = path.resolve(__dirname, '../../../package.json');      const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8')) as { version: string };      return pkg.version;    } catch {      return '0.0.0';    }  });   // Read CLAUDE.md files  app.post<{ Body: { projectRoot: string } }>('/api/read-claude-md', async (request) => {    try {      const { projectRoot } = request.body;      const result = await readAllClaudeMdFiles(projectRoot);      const files: Record<string, ClaudeMdFileInfo> = {};      result.files.forEach((info, key) => {        files[key] = info;      });      return files;    } catch (error) {      logger.error('Error in POST /api/read-claude-md:', error);      return {};    }  });   // Read directory CLAUDE.md  app.post<{ Body: { dirPath: string } }>('/api/read-directory-claude-md', async (request) => {    try {      const { dirPath } = request.body;      const info = await readDirectoryClaudeMd(dirPath);      return info;    } catch (error) {      logger.error('Error in POST /api/read-directory-claude-md:', error);      return {        path: request.body.dirPath,        exists: false,        charCount: 0,        estimatedTokens: 0,      };    }  });   // Read mentioned file  app.post<{ Body: { absolutePath: string; projectRoot: string; maxTokens?: number } }>(    '/api/read-mentioned-file',    async (request) => {      try {        const { absolutePath, projectRoot, maxTokens = 25000 } = request.body;         const validation = validateFilePath(absolutePath, projectRoot || null);        if (!validation.valid) {          return null;        }         const safePath = validation.normalizedPath!;         if (!fs.existsSync(safePath)) {          return null;        }         const stats = fs.statSync(safePath);        if (!stats.isFile()) {          return null;        }         const content = fs.readFileSync(safePath, 'utf8');        const estimatedTokens = countTokens(content);         if (estimatedTokens > maxTokens) {          return null;        }         return {          path: safePath,          exists: true,          charCount: content.length,          estimatedTokens,        };      } catch (error) {        logger.error(          `Error in POST /api/read-mentioned-file for ${request.body.absolutePath}:`,          error        );        return null;      }    }  );   // Open path - no-op in browser mode  app.post('/api/open-path', async () => {    return { success: false, error: 'Not available in browser mode' };  });   // Open external - no-op in browser mode  app.post<{ Body: { url: string } }>('/api/open-external', async () => {    return { success: false, error: 'Not available in browser mode' };  });}