woaru
Version:
Universal Project Setup Autopilot - Analyze and automatically configure development tools for ANY programming language
1,024 lines β’ 39.6 kB
JavaScript
import fs from 'fs-extra';
import * as path from 'path';
import * as os from 'os';
import https from 'https';
import { safeJsonParse } from '../utils/safeJsonParser.js';
import { fileURLToPath } from 'url';
import { dirname } from 'path';
import { SchemaValidator, } from '../schemas/ai-config.schema.js';
import { triggerHook } from '../core/HookSystem.js';
import chalk from 'chalk';
// ES module compatibility
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export class ToolsDatabaseManager {
cacheDir;
cacheFilePath;
aiModelsCacheFilePath;
defaultSourceUrl;
aiModelsSourceUrl;
localFallbackPath;
aiModelsLocalFallbackPath;
databasePath;
constructor() {
this.cacheDir = path.join(os.homedir(), '.woaru', 'cache');
this.cacheFilePath = path.join(this.cacheDir, 'tools.json');
this.aiModelsCacheFilePath = path.join(this.cacheDir, 'ai-models.json');
this.databasePath = this.cacheFilePath; // Set database path for hooks
this.defaultSourceUrl =
'https://raw.githubusercontent.com/iamthamanic/WOARU-WorkaroundUltra/main/tools.json';
this.aiModelsSourceUrl =
'https://raw.githubusercontent.com/iamthamanic/WOARU-WorkaroundUltra/main/ai-models.json';
// Fallback to local files in project root
this.localFallbackPath = path.join(__dirname, '..', '..', 'tools.json');
this.aiModelsLocalFallbackPath = path.join(__dirname, '..', '..', 'ai-models.json');
}
/**
* Gets the hybrid tools database, loading from cache or downloading if needed
*/
async getHybridDatabase() {
try {
// Ensure cache directory exists
await fs.ensureDir(this.cacheDir);
// Check if cached version exists
if (await fs.pathExists(this.cacheFilePath)) {
try {
const cachedData = await fs.readJson(this.cacheFilePath);
// Check if it's the new hybrid format
if (cachedData.schema_version === '2.0' &&
cachedData.core_tools &&
cachedData.experimental_tools) {
return cachedData;
}
else {
console.log('π WOARU: Outdated database format, downloading hybrid version...');
}
}
catch {
console.warn('π WOARU: Cached tools database is corrupted, downloading fresh copy...');
}
}
// No cache or outdated format - download fresh copy
console.log('π₯ WOARU: Downloading hybrid tools database...');
const freshData = await this.downloadHybridDatabase();
// Save to cache
await fs.writeJson(this.cacheFilePath, freshData, { spaces: 2 });
console.log('β
WOARU: Hybrid tools database cached successfully');
return freshData;
}
catch {
console.warn('β οΈ WOARU: Failed to download hybrid database, using local fallback');
return this.loadHybridLocalFallback();
}
}
/**
* Gets the legacy tools database format (for backward compatibility)
*/
async getDatabase() {
try {
// πͺ HOOK: beforeConfigLoad - KI-freundliche Regelwelt
try {
await triggerHook('onConfigLoad', {
configType: 'tools',
configPath: this.databasePath,
configData: null,
timestamp: new Date(),
});
}
catch (hookError) {
console.debug(`Hook error (onConfigLoad): ${hookError}`);
}
const hybridDb = await this.getHybridDatabase();
// π‘οΈ SCHEMA-VALIDIERUNG: Tools Database - KI-freundliche Regelwelt
try {
const validation = SchemaValidator.validateCompleteToolsDatabase(hybridDb);
if (!validation.success) {
console.warn(chalk.yellow('β οΈ Tools-Datenbank Schema-Validierung fehlgeschlagen:'));
validation.errors?.forEach(error => {
console.warn(chalk.yellow(` β’ ${error}`));
});
console.warn(chalk.gray('π‘ Verwende Fallback-Modus fΓΌr KompatibilitΓ€t'));
}
else {
console.log(chalk.green('β
Tools-Datenbank erfolgreich gegen Schema validiert'));
}
}
catch (validationError) {
console.debug(`Schema validation error: ${validationError}`);
}
// Convert hybrid database to legacy format for backward compatibility
const legacyDb = this.convertHybridToLegacy(hybridDb);
// πͺ HOOK: afterConfigLoad - KI-freundliche Regelwelt
try {
await triggerHook('onConfigLoad', {
configType: 'tools',
configPath: this.databasePath,
configData: legacyDb,
timestamp: new Date(),
});
}
catch (hookError) {
console.debug(`Hook error (onConfigLoad after): ${hookError}`);
}
return legacyDb;
}
catch (error) {
console.warn(chalk.yellow('β οΈ WOARU: Failed to get hybrid database, falling back to legacy:'), error instanceof Error ? error.message : error);
return this.loadLegacyDatabase();
}
}
/**
* Downloads the hybrid tools database from remote source
*/
async downloadHybridDatabase() {
return new Promise((resolve, reject) => {
const request = https.get(this.defaultSourceUrl, response => {
if (response.statusCode !== 200) {
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
return;
}
let data = '';
response.on('data', chunk => {
data += chunk;
});
response.on('end', () => {
try {
const parsedData = safeJsonParse(data);
if (!parsedData) {
throw new Error('Failed to parse tools database JSON');
}
// Validate hybrid format
if (!parsedData.core_tools || !parsedData.experimental_tools) {
reject(new Error('Invalid hybrid database format'));
return;
}
resolve(parsedData);
}
catch (error) {
reject(new Error(`Failed to parse hybrid JSON: ${error}`));
}
});
});
request.on('error', error => {
reject(error);
});
request.setTimeout(10000, () => {
request.destroy();
reject(new Error('Download timeout'));
});
});
}
/**
* Legacy database loading for backward compatibility
*/
async loadLegacyDatabase() {
try {
// Ensure cache directory exists
await fs.ensureDir(this.cacheDir);
// Check if cached version exists
if (await fs.pathExists(this.cacheFilePath)) {
try {
const cachedData = await fs.readJson(this.cacheFilePath);
// Check if cached data has legacy format
if (cachedData.categories && !cachedData.core_tools) {
// π Schema-Validierung fΓΌr Tools-Datenbank - KI-freundliche Regelwelt
// TODO: Implement proper validation for legacy tools database format
console.log(chalk.green('β
Tools database loaded (validation pending schema refactor)'));
return cachedData;
}
else {
console.log('π WOARU: Cached database is hybrid format, converting to legacy...');
const hybridData = cachedData;
return this.convertHybridToLegacy(hybridData);
}
}
catch {
console.warn('π WOARU: Cached tools database is corrupted, downloading fresh copy...');
}
}
// No cache - download fresh copy
console.log('π₯ WOARU: Downloading tools database...');
const freshData = await this.downloadDatabase();
// Save to cache
await fs.writeJson(this.cacheFilePath, freshData, { spaces: 2 });
console.log('β
WOARU: Tools database cached successfully');
return freshData;
}
catch {
console.warn('β οΈ WOARU: Failed to download tools database, using local fallback');
return this.loadLocalFallback();
}
}
/**
* Downloads the tools database from the remote source
*/
async downloadDatabase() {
return new Promise((resolve, reject) => {
const request = https.get(this.defaultSourceUrl, response => {
if (response.statusCode !== 200) {
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
return;
}
let data = '';
response.on('data', chunk => {
data += chunk;
});
response.on('end', () => {
try {
const parsedData = safeJsonParse(data);
if (!parsedData) {
throw new Error('Failed to parse tools database JSON');
}
resolve(parsedData);
}
catch (error) {
reject(new Error(`Failed to parse JSON: ${error}`));
}
});
});
request.on('error', error => {
reject(error);
});
request.setTimeout(10000, () => {
request.destroy();
reject(new Error('Download timeout'));
});
});
}
/**
* Loads the local fallback tools.json from project root
*/
async loadLocalFallback() {
try {
if (await fs.pathExists(this.localFallbackPath)) {
const localData = await fs.readJson(this.localFallbackPath);
return localData;
}
}
catch {
console.warn('β οΈ WOARU: Local fallback also failed');
}
// Ultimate fallback - minimal database
return this.getMinimalDatabase();
}
/**
* Returns a minimal database as last resort
*/
getMinimalDatabase() {
return {
version: '1.0.0',
lastUpdated: new Date().toISOString(),
categories: {
linting: {
description: 'Code quality tools',
tools: {
eslint: {
name: 'ESLint',
languages: ['javascript', 'typescript'],
frameworks: ['react', 'vue', 'angular'],
popularity: 95,
keywords: ['eslint'],
installCommand: 'npm install -D eslint',
description: 'JavaScript and TypeScript linter',
homepage: 'https://eslint.org',
isRecommended: true,
},
},
},
},
frameworks: {},
meta: {
sourceUrl: 'fallback',
updateFrequency: 'manual',
maintainers: ['WOARU'],
schemaVersion: '1.0',
},
};
}
/**
* Gets the last update time of the cached database
*/
async getCacheInfo() {
try {
if (await fs.pathExists(this.cacheFilePath)) {
const stats = await fs.stat(this.cacheFilePath);
const data = await fs.readJson(this.cacheFilePath);
return {
exists: true,
lastModified: stats.mtime,
version: data.version,
};
}
}
catch {
// Ignore errors
}
return { exists: false };
}
/**
* Forces a fresh download and cache update
*/
async forceUpdate() {
try {
console.log('π WOARU: Force updating tools database...');
const freshData = await this.downloadDatabase();
// Ensure cache directory exists
await fs.ensureDir(this.cacheDir);
// Save to cache
await fs.writeJson(this.cacheFilePath, freshData, { spaces: 2 });
console.log('β
WOARU: Tools database updated successfully');
return freshData;
}
catch (error) {
console.error('β WOARU: Failed to force update tools database:', error);
throw error;
}
}
/**
* Clears the cache
*/
async clearCache() {
try {
if (await fs.pathExists(this.cacheFilePath)) {
await fs.remove(this.cacheFilePath);
console.log('ποΈ WOARU: Tools database cache cleared');
}
}
catch (error) {
console.warn('β οΈ WOARU: Failed to clear cache:', error);
}
}
/**
* Gets tools by category
*/
async getToolsByCategory(category) {
const database = await this.getDatabase();
return database.categories[category]?.tools || {};
}
/**
* Gets recommended tools for a framework
*/
async getRecommendedToolsForFramework(framework) {
const database = await this.getDatabase();
return database.frameworks[framework]?.recommendedTools || {};
}
/**
* Searches for tools by keywords
*/
async searchToolsByKeywords(keywords) {
const database = await this.getDatabase();
const results = [];
Object.entries(database.categories).forEach(([categoryName, category]) => {
Object.entries(category.tools).forEach(([toolKey, tool]) => {
const hasKeyword = keywords.some(keyword => tool.keywords.some(toolKeyword => toolKeyword.toLowerCase().includes(keyword.toLowerCase())));
if (hasKeyword) {
results.push({
...tool,
key: toolKey,
category: categoryName,
});
}
});
});
return results;
}
/**
* Checks for updates in the background and updates cache if newer version available
* Enhanced version with version comparison and detailed logging
*/
async checkForUpdates() {
try {
// Get cache info
const cacheInfo = await this.getCacheInfo();
if (!cacheInfo.exists) {
// No cache exists, download fresh copy
console.log('π₯ WOARU: No local tools database found, downloading...');
await this.getDatabase();
return true;
}
// Check remote version info
const remoteVersionInfo = await this.getRemoteVersionInfo();
if (!remoteVersionInfo) {
return false; // Cannot determine remote version
}
// Compare versions and timestamps
const needsUpdate = this.shouldUpdate(cacheInfo, remoteVersionInfo);
if (needsUpdate) {
console.log('π WOARU: Newer tools database found, updating...');
console.log(` Local: ${cacheInfo.version || 'unknown'} β Remote: ${remoteVersionInfo.version}`);
// Download and cache new version
const freshData = await this.downloadDatabase();
await fs.writeJson(this.cacheFilePath, freshData, { spaces: 2 });
// Log update details
const toolCount = this.countToolsInDatabase(freshData);
console.log('π‘ WOARU tools database updated successfully');
console.log(` π ${toolCount.total} tools across ${toolCount.categories} categories`);
console.log(` π Version: ${freshData.version} (${freshData.lastUpdated})`);
return true;
}
return false; // No update needed
}
catch (error) {
// Enhanced error handling for debugging
if (process.env.WOARU_DEBUG) {
console.warn('β οΈ WOARU: Database update check failed:', error);
}
return false;
}
}
/**
* Gets the last-modified date from remote source using HEAD request
*/
async getRemoteLastModified() {
return new Promise(resolve => {
const request = https.request(this.defaultSourceUrl, { method: 'HEAD' }, response => {
const lastModified = response.headers['last-modified'];
if (lastModified) {
resolve(new Date(lastModified));
}
else {
resolve(null);
}
});
request.on('error', () => {
resolve(null);
});
request.setTimeout(5000, () => {
request.destroy();
resolve(null);
});
request.end();
});
}
backgroundInterval;
/**
* Starts background update checking (call this when WOARU starts)
*/
async startBackgroundUpdates() {
// Check for updates immediately (but don't wait)
this.checkForUpdates().catch(() => {
// Silently ignore errors in background
});
// Set up periodic checking every 24 hours
this.backgroundInterval = setInterval(async () => {
this.checkForUpdates().catch(() => {
// Silently ignore errors in background
});
}, 24 * 60 * 60 * 1000); // 24 hours
}
/**
* Stops background update checking
*/
stopBackgroundUpdates() {
if (this.backgroundInterval) {
clearInterval(this.backgroundInterval);
this.backgroundInterval = undefined;
}
}
/**
* Gets remote version information including version and last modified date
*/
async getRemoteVersionInfo() {
try {
// First try to get the file to read version
const remoteData = await this.downloadDatabase();
const lastModified = await this.getRemoteLastModified();
return {
version: remoteData.version,
lastModified: lastModified || new Date(),
};
}
catch {
return null;
}
}
/**
* Determines if local cache should be updated based on version and timestamp
*/
shouldUpdate(localInfo, remoteInfo) {
// Always update if no local version exists
if (!localInfo.exists || !localInfo.version) {
return true;
}
// Compare versions (semantic versioning)
if (this.isNewerVersion(remoteInfo.version, localInfo.version)) {
return true;
}
// Fallback to timestamp comparison if versions are same
if (localInfo.lastModified &&
remoteInfo.lastModified > localInfo.lastModified) {
return true;
}
return false;
}
/**
* Compares two semantic version strings
*/
isNewerVersion(remoteVersion, localVersion) {
const parseVersion = (version) => {
const parts = version.replace(/^v/, '').split('.').map(Number);
return {
major: parts[0] || 0,
minor: parts[1] || 0,
patch: parts[2] || 0,
};
};
const remote = parseVersion(remoteVersion);
const local = parseVersion(localVersion);
if (remote.major !== local.major)
return remote.major > local.major;
if (remote.minor !== local.minor)
return remote.minor > local.minor;
return remote.patch > local.patch;
}
/**
* Counts tools and categories in database for logging
*/
countToolsInDatabase(database) {
let total = 0;
const categories = Object.keys(database.categories).length;
Object.values(database.categories).forEach(category => {
total += Object.keys(category.tools).length;
});
return { total, categories };
}
/**
* Gets database statistics for debugging
*/
async getDatabaseStats() {
const database = await this.getDatabase();
const toolCount = this.countToolsInDatabase(database);
return {
version: database.version,
toolCount: toolCount.total,
categories: Object.keys(database.categories),
lastUpdated: database.lastUpdated,
};
}
// ========== HYBRID DATABASE METHODS ==========
/**
* Gets core tool configuration for a specific tool
*/
async getCoreToolConfig(toolName) {
try {
const hybridDb = await this.getHybridDatabase();
return hybridDb.core_tools[toolName] || null;
}
catch (error) {
console.warn(`Failed to get core tool config for ${toolName}:`, error);
return null;
}
}
/**
* Gets experimental tool configuration for a specific tool
*/
async getExperimentalToolConfig(toolName) {
try {
const hybridDb = await this.getHybridDatabase();
return hybridDb.experimental_tools[toolName] || null;
}
catch (error) {
console.warn(`Failed to get experimental tool config for ${toolName}:`, error);
return null;
}
}
/**
* Gets all core tools that support a specific file extension
*/
async getCoreToolsForFileExtension(fileExtension) {
try {
const hybridDb = await this.getHybridDatabase();
const coreTools = [];
Object.values(hybridDb.core_tools).forEach(tool => {
if (tool.fileExtensions.includes(fileExtension)) {
coreTools.push(tool);
}
});
return coreTools.sort((a, b) => b.popularity - a.popularity);
}
catch (error) {
console.warn(`Failed to get core tools for extension ${fileExtension}:`, error);
return [];
}
}
/**
* Gets all experimental tools that support a specific file extension
*/
async getExperimentalToolsForFileExtension(fileExtension) {
try {
const hybridDb = await this.getHybridDatabase();
const experimentalTools = [];
Object.values(hybridDb.experimental_tools).forEach(tool => {
if (tool.fileExtensions.includes(fileExtension)) {
experimentalTools.push(tool);
}
});
return experimentalTools.sort((a, b) => b.popularity - a.popularity);
}
catch (error) {
console.warn(`Failed to get experimental tools for extension ${fileExtension}:`, error);
return [];
}
}
/**
* Gets framework-specific tool recommendations
*/
async getFrameworkRecommendations(framework) {
try {
const hybridDb = await this.getHybridDatabase();
const recommendations = hybridDb.framework_recommendations[framework];
if (recommendations) {
return {
core_tools: recommendations.core_tools || [],
experimental_tools: recommendations.experimental_tools || [],
};
}
return null;
}
catch (error) {
console.warn(`Failed to get framework recommendations for ${framework}:`, error);
return null;
}
}
/**
* Checks if a tool is deprecated and returns successor info
*/
async getDeprecationInfo(toolName) {
try {
const hybridDb = await this.getHybridDatabase();
return hybridDb.deprecation_warnings[toolName] || null;
}
catch {
return null;
}
}
// ========== HELPER METHODS ==========
/**
* Converts hybrid database to legacy format for backward compatibility
*/
convertHybridToLegacy(hybridDb) {
const legacyDb = {
version: hybridDb.version,
lastUpdated: hybridDb.lastUpdated,
categories: {},
frameworks: {},
meta: {
sourceUrl: hybridDb.meta.source_url,
updateFrequency: hybridDb.meta.update_frequency,
maintainers: hybridDb.meta.maintainers,
schemaVersion: hybridDb.schema_version,
},
};
// Use legacy_categories if available, otherwise create from core_tools
if (hybridDb.legacy_categories) {
legacyDb.categories =
hybridDb.legacy_categories;
}
else {
// Convert core_tools to legacy category format
legacyDb.categories = this.createLegacyCategoriesFromCoreTools(hybridDb);
}
return legacyDb;
}
/**
* Creates legacy categories structure from core tools
*/
createLegacyCategoriesFromCoreTools(hybridDb) {
const categories = {
linting: {
description: 'Code quality and style checking tools',
tools: {},
},
formatting: { description: 'Code formatting tools', tools: {} },
security: {
description: 'Security and vulnerability scanning tools',
tools: {},
},
};
// Map core tools to categories based on tool type
Object.entries(hybridDb.core_tools).forEach(([toolKey, tool]) => {
let category = 'linting'; // default
if (tool.name.toLowerCase().includes('format') ||
toolKey === 'prettier') {
category = 'formatting';
}
else if (tool.name.toLowerCase().includes('security') ||
tool.name.toLowerCase().includes('secure')) {
category = 'security';
}
categories[category].tools[toolKey] = {
name: tool.name,
languages: tool.languages,
frameworks: tool.frameworks,
popularity: tool.popularity,
keywords: [tool.metadata.npm_package || toolKey],
installCommand: `npm install -D ${tool.metadata.npm_package || toolKey}`,
configFiles: tool.config_files,
description: tool.description,
homepage: `https://github.com/${tool.metadata.github_repo}`,
isRecommended: tool.priority === 'high' || tool.priority === 'critical',
isDeprecated: tool.isDeprecated,
};
});
return categories;
}
/**
* Loads hybrid local fallback
*/
async loadHybridLocalFallback() {
try {
if (await fs.pathExists(this.localFallbackPath)) {
const localData = await fs.readJson(this.localFallbackPath);
// Check if it's hybrid format
if (localData.schema_version === '2.0' && localData.core_tools) {
return localData;
}
}
}
catch {
console.warn('β οΈ WOARU: Local hybrid fallback also failed');
}
// Ultimate fallback - minimal hybrid database
return this.getMinimalHybridDatabase();
}
/**
* Returns minimal hybrid database as last resort
*/
getMinimalHybridDatabase() {
return {
version: '3.2.0',
lastUpdated: new Date().toISOString(),
schema_version: '2.0',
core_tools: {
eslint: {
name: 'ESLint',
description: 'JavaScript and TypeScript linter',
languages: ['javascript', 'typescript'],
fileExtensions: ['.js', '.jsx', '.ts', '.tsx'],
frameworks: ['react', 'vue', 'angular'],
recommended_flags: ['--fix'],
config_files: ['.eslintrc.js', '.eslintrc.json'],
isDeprecated: false,
popularity: 95,
priority: 'high',
plugin_class: 'EslintPlugin',
metadata: {
npm_package: 'eslint',
github_repo: 'eslint/eslint',
weekly_downloads: 25000000,
last_check: new Date().toISOString(),
},
},
},
experimental_tools: {},
deprecation_warnings: {},
framework_recommendations: {},
meta: {
source_url: 'fallback',
update_frequency: 'manual',
maintainers: ['WOARU'],
schema_documentation: '',
version_history: [],
},
};
}
// ========== AI MODELS DATABASE METHODS ==========
/**
* Gets the AI models database, loading from cache or downloading if needed
*/
async getAIModelsDatabase() {
try {
// First try local file for development
if (await fs.pathExists(this.aiModelsLocalFallbackPath)) {
try {
const localData = await fs.readJson(this.aiModelsLocalFallbackPath);
if (localData.llm_providers && localData.version) {
console.log('β
WOARU: Using local AI models database');
return localData;
}
}
catch {
// Continue to cache/remote fallback
}
}
// Ensure cache directory exists
await fs.ensureDir(this.cacheDir);
// Check if cached version exists
if (await fs.pathExists(this.aiModelsCacheFilePath)) {
try {
const cachedData = await fs.readJson(this.aiModelsCacheFilePath);
// Check if it's a valid AI models database
if (cachedData.llm_providers && cachedData.version) {
return cachedData;
}
else {
console.log('π WOARU: Outdated AI models database format, downloading new version...');
}
}
catch {
console.warn('π WOARU: Cached AI models database is corrupted, downloading fresh copy...');
}
}
// No cache or outdated format - download fresh copy
console.log('π₯ WOARU: Downloading AI models database...');
const freshData = await this.downloadAIModelsDatabase();
// Save to cache
await fs.writeJson(this.aiModelsCacheFilePath, freshData, { spaces: 2 });
console.log('β
WOARU: AI models database cached successfully');
return freshData;
}
catch {
console.warn('β οΈ WOARU: Failed to download AI models database, using local fallback');
return this.loadAIModelsLocalFallback();
}
}
/**
* Downloads the AI models database from remote source
*/
async downloadAIModelsDatabase() {
return new Promise((resolve, reject) => {
const request = https.get(this.aiModelsSourceUrl, response => {
if (response.statusCode !== 200) {
reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
return;
}
let data = '';
response.on('data', chunk => {
data += chunk;
});
response.on('end', () => {
try {
const parsedData = safeJsonParse(data);
if (!parsedData) {
throw new Error('Failed to parse AI models database JSON');
}
// Validate AI models database format
if (!parsedData.llm_providers || !parsedData.version) {
reject(new Error('Invalid AI models database format'));
return;
}
resolve(parsedData);
}
catch (error) {
reject(new Error(`Failed to parse AI models JSON: ${error}`));
}
});
});
request.on('error', error => {
reject(error);
});
request.setTimeout(10000, () => {
request.destroy();
reject(new Error('Download timeout'));
});
});
}
/**
* Loads the local fallback ai-models.json from project root
*/
async loadAIModelsLocalFallback() {
try {
if (await fs.pathExists(this.aiModelsLocalFallbackPath)) {
const localData = await fs.readJson(this.aiModelsLocalFallbackPath);
return localData;
}
}
catch {
console.warn('β οΈ WOARU: Local AI models fallback also failed');
}
// Ultimate fallback - minimal AI models database
return this.getMinimalAIModelsDatabase();
}
/**
* Returns a minimal AI models database as last resort
*/
getMinimalAIModelsDatabase() {
return {
version: '1.0.0',
lastUpdated: new Date().toISOString(),
llm_providers: {
anthropic: {
name: 'Anthropic Claude',
description: 'Advanced AI assistant models by Anthropic',
apiKeyEnvVar: 'ANTHROPIC_API_KEY',
baseUrl: 'https://api.anthropic.com/v1/messages',
providerType: 'anthropic',
headers: {
'anthropic-version': '2023-06-01',
},
bodyTemplate: '{"model":"{model}","max_tokens":4000,"temperature":0.1,"messages":[{"role":"user","content":"{prompt}\\n\\nCode to analyze:\\n```{language}\\n{code}\\n```"}]}',
timeout: 30000,
maxTokens: 4000,
temperature: 0.1,
models: [
{
id: 'claude-3-5-sonnet-20241022',
name: 'Claude 3.5 Sonnet',
description: 'Most capable model with superior reasoning',
isLatest: true,
category: 'flagship',
contextWindow: 200000,
supportedFeatures: ['code_analysis', 'reasoning', 'writing'],
},
],
},
},
};
}
/**
* Gets all available AI providers
*/
async getAIProviders() {
const database = await this.getAIModelsDatabase();
return database.llm_providers;
}
/**
* Gets models for a specific provider
*/
async getModelsForProvider(providerName) {
const database = await this.getAIModelsDatabase();
return database.llm_providers[providerName]?.models || [];
}
/**
* Gets all available models from all providers
*/
async getAllAIModels() {
const database = await this.getAIModelsDatabase();
const allModels = [];
Object.entries(database.llm_providers).forEach(([providerName, provider]) => {
provider.models.forEach(model => {
allModels.push({
...model,
provider: providerName,
});
});
});
return allModels;
}
/**
* Gets latest/flagship models from all providers
*/
async getLatestAIModels() {
const allModels = await this.getAllAIModels();
return allModels.filter(model => model.isLatest || model.category === 'flagship');
}
/**
* Gets models by category (flagship, fast, balanced, etc.)
*/
async getModelsByCategory(category) {
const allModels = await this.getAllAIModels();
return allModels.filter(model => model.category === category);
}
/**
* Gets a specific model by ID across all providers
*/
async getModelById(modelId) {
const allModels = await this.getAllAIModels();
return allModels.find(model => model.id === modelId) || null;
}
/**
* Gets provider configuration for a specific provider
*/
async getProviderConfig(providerName) {
const database = await this.getAIModelsDatabase();
return database.llm_providers[providerName] || null;
}
/**
* Forces update of AI models database
*/
async forceUpdateAIModels() {
try {
console.log('π WOARU: Force updating AI models database...');
const freshData = await this.downloadAIModelsDatabase();
// Ensure cache directory exists
await fs.ensureDir(this.cacheDir);
// Save to cache
await fs.writeJson(this.aiModelsCacheFilePath, freshData, { spaces: 2 });
console.log('β
WOARU: AI models database updated successfully');
return freshData;
}
catch (error) {
console.error('β WOARU: Failed to force update AI models database:', error);
throw error;
}
}
/**
* Gets AI models database statistics
*/
async getAIModelsStats() {
const database = await this.getAIModelsDatabase();
const providers = Object.keys(database.llm_providers);
let totalModels = 0;
providers.forEach(providerName => {
totalModels += database.llm_providers[providerName].models.length;
});
return {
version: database.version,
providers: providers.length,
totalModels,
providerNames: providers,
lastUpdated: database.lastUpdated,
};
}
}
//# sourceMappingURL=ToolsDatabaseManager.js.map