- Заполнены заглушки: user-friendly-messages, health, aria, keyboard - backend: core/auth.py, /api/v1/stats; cached-api → backend-client при USE_MOCK_DATA=false - .env.example, middleware auth (skip при USE_MOCK_DATA), убраны неиспользуемые deps - Страницы: airworthiness, maintenance, defects, modifications; AircraftAddModal, Sidebar - Главная страница: REFLY — Контроль лётной годности (вместо Numerology App) - Линт/скрипты: eslintrc, security, cleanup, logs, api inbox/knowledge Co-authored-by: Cursor <cursoragent@cursor.com>
171 lines
5.6 KiB
JavaScript
Executable File
171 lines
5.6 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
||
/**
|
||
* Скрипт для добавления всех файлов из knowledge/ в manifest.json
|
||
* Приводит все записи к единому формату с обязательными полями
|
||
*/
|
||
|
||
import fs from 'fs';
|
||
import path from 'path';
|
||
import { fileURLToPath } from 'url';
|
||
|
||
const __filename = fileURLToPath(import.meta.url);
|
||
const __dirname = path.dirname(__filename);
|
||
|
||
const MANIFEST_PATH = path.join(__dirname, '../index/manifest.json');
|
||
const KNOWLEDGE_DIR = path.join(__dirname, '../knowledge');
|
||
|
||
// Ключевые документы для статуса approved (3-5 документов)
|
||
const KEY_DOCUMENTS_PATTERNS = [
|
||
/papa_project_bootstrap/i,
|
||
/145\.1в/i,
|
||
/рц-ап-145/i,
|
||
/tv3_117_kniga_1.*turboval/i,
|
||
/tech_cards_registry/i
|
||
];
|
||
|
||
function getDocumentType(filePath) {
|
||
const dir = path.dirname(filePath).split(path.sep).pop();
|
||
if (dir === 'reglaments') return 'reglament';
|
||
if (dir === 'guides') return 'template';
|
||
if (dir === 'samples') return 'sample';
|
||
return 'reglament';
|
||
}
|
||
|
||
function getDomain(filePath, fileName) {
|
||
const lowerName = fileName.toLowerCase();
|
||
if (lowerName.includes('tmc') || lowerName.includes('tv3') || lowerName.includes('двигател') || lowerName.includes('byulleten')) return 'tmc';
|
||
if (lowerName.includes('145') || lowerName.includes('183') || lowerName.includes('регламент') || lowerName.includes('руководство')) return 'regulations';
|
||
if (lowerName.includes('анкет') || lowerName.includes('hr')) return 'hr';
|
||
if (lowerName.includes('инспекц')) return 'inspection';
|
||
return 'core';
|
||
}
|
||
|
||
function generateId(type, index) {
|
||
const prefix = type === 'reglament' ? 'reg' : type === 'template' ? 'guide' : 'sample';
|
||
return `${prefix}-${String(index).padStart(3, '0')}`;
|
||
}
|
||
|
||
function getTitle(fileName) {
|
||
// Убираем расширение
|
||
let title = fileName.replace(/\.[^.]+$/, '');
|
||
// Убираем "— копия" и подобное
|
||
title = title.replace(/\s*—\s*копия\s*/gi, '').trim();
|
||
// Если название слишком длинное, обрезаем
|
||
if (title.length > 100) {
|
||
title = title.substring(0, 97) + '...';
|
||
}
|
||
return title || fileName;
|
||
}
|
||
|
||
function isKeyDocument(fileName) {
|
||
return KEY_DOCUMENTS_PATTERNS.some(pattern => pattern.test(fileName));
|
||
}
|
||
|
||
function getAllFiles() {
|
||
const files = [];
|
||
|
||
['reglaments', 'guides', 'samples'].forEach(dir => {
|
||
const dirPath = path.join(KNOWLEDGE_DIR, dir);
|
||
if (!fs.existsSync(dirPath)) return;
|
||
|
||
const dirFiles = fs.readdirSync(dirPath)
|
||
.filter(file => {
|
||
const filePath = path.join(dirPath, file);
|
||
const stat = fs.statSync(filePath);
|
||
return stat.isFile() && file !== '.DS_Store' && file !== 'README.md';
|
||
})
|
||
.map(file => ({
|
||
fileName: file,
|
||
filePath: path.join(dir, file),
|
||
fullPath: path.join(dirPath, file)
|
||
}));
|
||
|
||
files.push(...dirFiles);
|
||
});
|
||
|
||
return files;
|
||
}
|
||
|
||
function updateManifest() {
|
||
// console.log('🔍 Сканирование файлов в knowledge/...\n');
|
||
|
||
// Получаем все файлы
|
||
const allFiles = getAllFiles();
|
||
console.log(`Найдено файлов: ${allFiles.length}\n`);
|
||
|
||
// Генерируем документы для всех файлов
|
||
const documents = [];
|
||
let regIndex = 1;
|
||
let guideIndex = 1;
|
||
let sampleIndex = 1;
|
||
|
||
// Сортируем файлы для консистентности
|
||
allFiles.sort((a, b) => {
|
||
const typeA = getDocumentType(a.filePath);
|
||
const typeB = getDocumentType(b.filePath);
|
||
const typeOrder = { reglament: 0, template: 1, sample: 2 };
|
||
if (typeOrder[typeA] !== typeOrder[typeB]) {
|
||
return typeOrder[typeA] - typeOrder[typeB];
|
||
}
|
||
return a.fileName.localeCompare(b.fileName);
|
||
});
|
||
|
||
allFiles.forEach(file => {
|
||
const relativePath = `knowledge/${file.filePath}`;
|
||
const type = getDocumentType(relativePath);
|
||
|
||
// Генерируем ID
|
||
let id;
|
||
if (type === 'reglament') {
|
||
id = generateId('reglament', regIndex++);
|
||
} else if (type === 'template') {
|
||
id = generateId('template', guideIndex++);
|
||
} else {
|
||
id = generateId('sample', sampleIndex++);
|
||
}
|
||
|
||
const doc = {
|
||
id,
|
||
title: getTitle(file.fileName),
|
||
path: relativePath,
|
||
type,
|
||
domain: getDomain(relativePath, file.fileName),
|
||
version: '1.0.0',
|
||
status: isKeyDocument(file.fileName) ? 'approved' : 'draft'
|
||
};
|
||
|
||
documents.push(doc);
|
||
});
|
||
|
||
// Читаем текущий manifest
|
||
const manifest = JSON.parse(fs.readFileSync(MANIFEST_PATH, 'utf8'));
|
||
|
||
// Обновляем manifest
|
||
manifest.documents = documents;
|
||
manifest.manifest.lastUpdated = new Date().toISOString();
|
||
|
||
// Обновляем метаданные
|
||
const statusBreakdown = { approved: 0, draft: 0, deprecated: 0 };
|
||
const fileTypes = {};
|
||
|
||
documents.forEach(doc => {
|
||
statusBreakdown[doc.status] = (statusBreakdown[doc.status] || 0) + 1;
|
||
const ext = path.extname(doc.path).slice(1).toLowerCase();
|
||
fileTypes[ext] = (fileTypes[ext] || 0) + 1;
|
||
});
|
||
|
||
manifest.metadata.documentCount = documents.length;
|
||
manifest.metadata.statusBreakdown = statusBreakdown;
|
||
manifest.metadata.fileTypes = fileTypes;
|
||
|
||
// Сохраняем
|
||
fs.writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
|
||
|
||
console.log(`✅ Обновлено документов: ${documents.length}`);
|
||
console.log(` - Approved: ${statusBreakdown.approved}`);
|
||
console.log(` - Draft: ${statusBreakdown.draft}`);
|
||
console.log(` - Deprecated: ${statusBreakdown.deprecated}\n`);
|
||
}
|
||
|
||
updateManifest();
|