chore: recovery checkpoint - v3.0 API successfully recovered
CRITICAL CHECKPOINT - DO NOT PUSH TO GITHUB Recovery Status: - Successfully recovered brainy.ts from compiled JavaScript - All core v3.0 API methods functional (add, get, update, delete, relate, find, etc.) - Neural subsystem intact (562KB embedded patterns, NLP working) - Augmentation pipeline operational (20+ augmentations) - HNSW clustering system complete - Triple Intelligence compiled (needs constructor fix) - Test suite validates functionality Changes preserved: - 898 files with changes from last 3 days - 144,475 insertions - All augmentation improvements - All test coverage enhancements - Complete v3.0 feature set This is a LOCAL checkpoint only - contains recovered work after corruption incident. Created backup in .backups/brainy-full-20250910-151314.tar.gz Branch: recovery-checkpoint-20250910-151433 Date: Wed Sep 10 03:18:04 PM PDT 2025
This commit is contained in:
parent
f65455fb22
commit
8ff382ca3b
895 changed files with 143654 additions and 28268 deletions
142
.recovery-workspace/dist-backup-20250910-141917/augmentations/discovery/catalogDiscovery.d.ts
vendored
Normal file
142
.recovery-workspace/dist-backup-20250910-141917/augmentations/discovery/catalogDiscovery.d.ts
vendored
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
* Brain-Cloud Catalog Discovery
|
||||
*
|
||||
* Discovers augmentations available in the brain-cloud catalog
|
||||
* Handles free, premium, and community augmentations
|
||||
*/
|
||||
import { AugmentationManifest } from '../manifest.js';
|
||||
export interface CatalogAugmentation {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
longDescription?: string;
|
||||
category: string;
|
||||
status: 'available' | 'coming_soon' | 'deprecated';
|
||||
tier: 'free' | 'premium' | 'enterprise';
|
||||
price?: {
|
||||
monthly?: number;
|
||||
yearly?: number;
|
||||
oneTime?: number;
|
||||
};
|
||||
manifest?: AugmentationManifest;
|
||||
source: 'catalog';
|
||||
cdnUrl?: string;
|
||||
npmPackage?: string;
|
||||
githubRepo?: string;
|
||||
author?: {
|
||||
name: string;
|
||||
url?: string;
|
||||
};
|
||||
metrics?: {
|
||||
installations: number;
|
||||
rating: number;
|
||||
reviews: number;
|
||||
};
|
||||
requirements?: {
|
||||
minBrainyVersion?: string;
|
||||
maxBrainyVersion?: string;
|
||||
dependencies?: string[];
|
||||
};
|
||||
}
|
||||
export interface CatalogOptions {
|
||||
apiUrl?: string;
|
||||
apiKey?: string;
|
||||
cache?: boolean;
|
||||
cacheTimeout?: number;
|
||||
}
|
||||
export interface CatalogFilters {
|
||||
category?: string;
|
||||
tier?: 'free' | 'premium' | 'enterprise';
|
||||
status?: 'available' | 'coming_soon' | 'deprecated';
|
||||
search?: string;
|
||||
installed?: boolean;
|
||||
minRating?: number;
|
||||
}
|
||||
/**
|
||||
* Brain-Cloud Catalog Discovery
|
||||
*/
|
||||
export declare class CatalogDiscovery {
|
||||
private apiUrl;
|
||||
private apiKey?;
|
||||
private cache;
|
||||
private cacheTimeout;
|
||||
constructor(options?: CatalogOptions);
|
||||
/**
|
||||
* Discover augmentations from catalog
|
||||
*/
|
||||
discover(filters?: CatalogFilters): Promise<CatalogAugmentation[]>;
|
||||
/**
|
||||
* Get specific augmentation details
|
||||
*/
|
||||
getAugmentation(id: string): Promise<CatalogAugmentation | null>;
|
||||
/**
|
||||
* Get augmentation manifest
|
||||
*/
|
||||
getManifest(id: string): Promise<AugmentationManifest | null>;
|
||||
/**
|
||||
* Get CDN URL for dynamic loading
|
||||
*/
|
||||
getCDNUrl(id: string): Promise<string | null>;
|
||||
/**
|
||||
* Check if user has access to augmentation
|
||||
*/
|
||||
checkAccess(id: string): Promise<{
|
||||
hasAccess: boolean;
|
||||
requiresPurchase?: boolean;
|
||||
requiredTier?: string;
|
||||
}>;
|
||||
/**
|
||||
* Purchase/activate augmentation
|
||||
*/
|
||||
purchase(id: string, licenseKey?: string): Promise<{
|
||||
success: boolean;
|
||||
cdnUrl?: string;
|
||||
npmPackage?: string;
|
||||
licenseKey?: string;
|
||||
}>;
|
||||
/**
|
||||
* Get user's purchased augmentations
|
||||
*/
|
||||
getPurchased(): Promise<CatalogAugmentation[]>;
|
||||
/**
|
||||
* Get categories
|
||||
*/
|
||||
getCategories(): Promise<Array<{
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
icon?: string;
|
||||
}>>;
|
||||
/**
|
||||
* Search augmentations
|
||||
*/
|
||||
search(query: string): Promise<CatalogAugmentation[]>;
|
||||
/**
|
||||
* Get trending augmentations
|
||||
*/
|
||||
getTrending(limit?: number): Promise<CatalogAugmentation[]>;
|
||||
/**
|
||||
* Get recommended augmentations
|
||||
*/
|
||||
getRecommended(): Promise<CatalogAugmentation[]>;
|
||||
/**
|
||||
* Transform catalog data
|
||||
*/
|
||||
private transformCatalogData;
|
||||
/**
|
||||
* Transform single augmentation
|
||||
*/
|
||||
private transformAugmentation;
|
||||
/**
|
||||
* Get request headers
|
||||
*/
|
||||
private getHeaders;
|
||||
/**
|
||||
* Clear cache
|
||||
*/
|
||||
clearCache(): void;
|
||||
/**
|
||||
* Set API key
|
||||
*/
|
||||
setApiKey(apiKey: string): void;
|
||||
}
|
||||
|
|
@ -0,0 +1,249 @@
|
|||
/**
|
||||
* Brain-Cloud Catalog Discovery
|
||||
*
|
||||
* Discovers augmentations available in the brain-cloud catalog
|
||||
* Handles free, premium, and community augmentations
|
||||
*/
|
||||
/**
|
||||
* Brain-Cloud Catalog Discovery
|
||||
*/
|
||||
export class CatalogDiscovery {
|
||||
constructor(options = {}) {
|
||||
this.cache = new Map();
|
||||
this.apiUrl = options.apiUrl || 'https://api.soulcraft.com/brain-cloud';
|
||||
this.apiKey = options.apiKey;
|
||||
this.cacheTimeout = options.cacheTimeout || 5 * 60 * 1000; // 5 minutes
|
||||
}
|
||||
/**
|
||||
* Discover augmentations from catalog
|
||||
*/
|
||||
async discover(filters = {}) {
|
||||
const cacheKey = JSON.stringify(filters);
|
||||
// Check cache
|
||||
if (this.cache.has(cacheKey)) {
|
||||
const cached = this.cache.get(cacheKey);
|
||||
if (Date.now() - cached.timestamp < this.cacheTimeout) {
|
||||
return cached.data;
|
||||
}
|
||||
}
|
||||
// Build query parameters
|
||||
const params = new URLSearchParams();
|
||||
if (filters.category)
|
||||
params.append('category', filters.category);
|
||||
if (filters.tier)
|
||||
params.append('tier', filters.tier);
|
||||
if (filters.status)
|
||||
params.append('status', filters.status);
|
||||
if (filters.search)
|
||||
params.append('q', filters.search);
|
||||
if (filters.minRating)
|
||||
params.append('minRating', filters.minRating.toString());
|
||||
// Fetch from API
|
||||
const response = await fetch(`${this.apiUrl}/augmentations/discover?${params}`, {
|
||||
headers: this.getHeaders()
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch catalog: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
const augmentations = this.transformCatalogData(data);
|
||||
// Cache result
|
||||
this.cache.set(cacheKey, {
|
||||
data: augmentations,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
return augmentations;
|
||||
}
|
||||
/**
|
||||
* Get specific augmentation details
|
||||
*/
|
||||
async getAugmentation(id) {
|
||||
const response = await fetch(`${this.apiUrl}/augmentations/${id}`, {
|
||||
headers: this.getHeaders()
|
||||
});
|
||||
if (!response.ok) {
|
||||
if (response.status === 404)
|
||||
return null;
|
||||
throw new Error(`Failed to fetch augmentation: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return this.transformAugmentation(data);
|
||||
}
|
||||
/**
|
||||
* Get augmentation manifest
|
||||
*/
|
||||
async getManifest(id) {
|
||||
const response = await fetch(`${this.apiUrl}/augmentations/${id}/manifest`, {
|
||||
headers: this.getHeaders()
|
||||
});
|
||||
if (!response.ok) {
|
||||
if (response.status === 404)
|
||||
return null;
|
||||
throw new Error(`Failed to fetch manifest: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
/**
|
||||
* Get CDN URL for dynamic loading
|
||||
*/
|
||||
async getCDNUrl(id) {
|
||||
const aug = await this.getAugmentation(id);
|
||||
return aug?.cdnUrl || null;
|
||||
}
|
||||
/**
|
||||
* Check if user has access to augmentation
|
||||
*/
|
||||
async checkAccess(id) {
|
||||
if (!this.apiKey) {
|
||||
// No API key, only free augmentations
|
||||
const aug = await this.getAugmentation(id);
|
||||
return {
|
||||
hasAccess: aug?.tier === 'free',
|
||||
requiresPurchase: aug?.tier !== 'free',
|
||||
requiredTier: aug?.tier
|
||||
};
|
||||
}
|
||||
const response = await fetch(`${this.apiUrl}/augmentations/${id}/access`, {
|
||||
headers: this.getHeaders()
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to check access: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
/**
|
||||
* Purchase/activate augmentation
|
||||
*/
|
||||
async purchase(id, licenseKey) {
|
||||
const body = licenseKey ? { licenseKey } : {};
|
||||
const response = await fetch(`${this.apiUrl}/augmentations/${id}/purchase`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...this.getHeaders(),
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to purchase: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
/**
|
||||
* Get user's purchased augmentations
|
||||
*/
|
||||
async getPurchased() {
|
||||
if (!this.apiKey) {
|
||||
return [];
|
||||
}
|
||||
const response = await fetch(`${this.apiUrl}/user/augmentations`, {
|
||||
headers: this.getHeaders()
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch purchased: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return this.transformCatalogData(data);
|
||||
}
|
||||
/**
|
||||
* Get categories
|
||||
*/
|
||||
async getCategories() {
|
||||
const response = await fetch(`${this.apiUrl}/augmentations/categories`, {
|
||||
headers: this.getHeaders()
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch categories: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
/**
|
||||
* Search augmentations
|
||||
*/
|
||||
async search(query) {
|
||||
return this.discover({ search: query });
|
||||
}
|
||||
/**
|
||||
* Get trending augmentations
|
||||
*/
|
||||
async getTrending(limit = 10) {
|
||||
const response = await fetch(`${this.apiUrl}/augmentations/trending?limit=${limit}`, {
|
||||
headers: this.getHeaders()
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch trending: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return this.transformCatalogData(data);
|
||||
}
|
||||
/**
|
||||
* Get recommended augmentations
|
||||
*/
|
||||
async getRecommended() {
|
||||
if (!this.apiKey) {
|
||||
// Return popular free augmentations
|
||||
return this.discover({ tier: 'free', minRating: 4 });
|
||||
}
|
||||
const response = await fetch(`${this.apiUrl}/augmentations/recommended`, {
|
||||
headers: this.getHeaders()
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to fetch recommended: ${response.statusText}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return this.transformCatalogData(data);
|
||||
}
|
||||
/**
|
||||
* Transform catalog data
|
||||
*/
|
||||
transformCatalogData(data) {
|
||||
return data.map(item => this.transformAugmentation(item));
|
||||
}
|
||||
/**
|
||||
* Transform single augmentation
|
||||
*/
|
||||
transformAugmentation(item) {
|
||||
return {
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
description: item.description,
|
||||
longDescription: item.longDescription,
|
||||
category: item.category,
|
||||
status: item.status || 'available',
|
||||
tier: item.tier || 'free',
|
||||
price: item.price,
|
||||
manifest: item.manifest,
|
||||
source: 'catalog',
|
||||
cdnUrl: item.cdnUrl || `https://cdn.soulcraft.com/augmentations/${item.id}@latest`,
|
||||
npmPackage: item.npmPackage,
|
||||
githubRepo: item.githubRepo,
|
||||
author: item.author,
|
||||
metrics: item.metrics,
|
||||
requirements: item.requirements
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Get request headers
|
||||
*/
|
||||
getHeaders() {
|
||||
const headers = {};
|
||||
if (this.apiKey) {
|
||||
headers['Authorization'] = `Bearer ${this.apiKey}`;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
/**
|
||||
* Clear cache
|
||||
*/
|
||||
clearCache() {
|
||||
this.cache.clear();
|
||||
}
|
||||
/**
|
||||
* Set API key
|
||||
*/
|
||||
setApiKey(apiKey) {
|
||||
this.apiKey = apiKey;
|
||||
this.clearCache(); // Clear cache when API key changes
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=catalogDiscovery.js.map
|
||||
File diff suppressed because one or more lines are too long
84
.recovery-workspace/dist-backup-20250910-141917/augmentations/discovery/localDiscovery.d.ts
vendored
Normal file
84
.recovery-workspace/dist-backup-20250910-141917/augmentations/discovery/localDiscovery.d.ts
vendored
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* Local Augmentation Discovery
|
||||
*
|
||||
* Discovers augmentations installed locally in node_modules
|
||||
* and built-in augmentations that ship with Brainy
|
||||
*/
|
||||
import { AugmentationManifest } from '../manifest.js';
|
||||
export interface LocalAugmentation {
|
||||
id: string;
|
||||
name: string;
|
||||
source: 'builtin' | 'npm' | 'local';
|
||||
path: string;
|
||||
manifest?: AugmentationManifest;
|
||||
package?: {
|
||||
name: string;
|
||||
version: string;
|
||||
description?: string;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Discovers augmentations installed locally
|
||||
*/
|
||||
export declare class LocalAugmentationDiscovery {
|
||||
private options;
|
||||
private builtInAugmentations;
|
||||
private installedAugmentations;
|
||||
constructor(options?: {
|
||||
brainyPath?: string;
|
||||
projectPath?: string;
|
||||
scanNodeModules?: boolean;
|
||||
});
|
||||
/**
|
||||
* Register built-in augmentations that ship with Brainy
|
||||
*/
|
||||
private registerBuiltIn;
|
||||
/**
|
||||
* Find Brainy installation path
|
||||
*/
|
||||
private findBrainyPath;
|
||||
/**
|
||||
* Discover all augmentations
|
||||
*/
|
||||
discoverAll(): Promise<LocalAugmentation[]>;
|
||||
/**
|
||||
* Scan node_modules for installed augmentations
|
||||
*/
|
||||
private scanNodeModules;
|
||||
/**
|
||||
* Scan local project for augmentations
|
||||
*/
|
||||
private scanLocalProject;
|
||||
/**
|
||||
* Load augmentation from package
|
||||
*/
|
||||
private loadPackageAugmentation;
|
||||
/**
|
||||
* Load package.json
|
||||
*/
|
||||
private loadPackageJson;
|
||||
/**
|
||||
* Convert name to human-readable format
|
||||
*/
|
||||
private humanizeName;
|
||||
/**
|
||||
* Get built-in augmentations
|
||||
*/
|
||||
getBuiltIn(): LocalAugmentation[];
|
||||
/**
|
||||
* Get installed augmentations
|
||||
*/
|
||||
getInstalled(): LocalAugmentation[];
|
||||
/**
|
||||
* Check if augmentation is installed
|
||||
*/
|
||||
isInstalled(id: string): boolean;
|
||||
/**
|
||||
* Get import path for augmentation
|
||||
*/
|
||||
getImportPath(id: string): string | null;
|
||||
/**
|
||||
* Load augmentation module dynamically
|
||||
*/
|
||||
loadAugmentation(id: string): Promise<any>;
|
||||
}
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
/**
|
||||
* Local Augmentation Discovery
|
||||
*
|
||||
* Discovers augmentations installed locally in node_modules
|
||||
* and built-in augmentations that ship with Brainy
|
||||
*/
|
||||
import { existsSync, readdirSync, readFileSync } from 'fs';
|
||||
import { join } from 'path';
|
||||
/**
|
||||
* Discovers augmentations installed locally
|
||||
*/
|
||||
export class LocalAugmentationDiscovery {
|
||||
constructor(options = {}) {
|
||||
this.options = options;
|
||||
this.builtInAugmentations = new Map();
|
||||
this.installedAugmentations = new Map();
|
||||
this.options = {
|
||||
brainyPath: this.options.brainyPath || this.findBrainyPath(),
|
||||
projectPath: this.options.projectPath || process.cwd(),
|
||||
scanNodeModules: this.options.scanNodeModules ?? true
|
||||
};
|
||||
// Register built-in augmentations
|
||||
this.registerBuiltIn();
|
||||
}
|
||||
/**
|
||||
* Register built-in augmentations that ship with Brainy
|
||||
*/
|
||||
registerBuiltIn() {
|
||||
const builtIn = [
|
||||
{ id: 'wal', name: 'Write-Ahead Log', path: 'walAugmentation' },
|
||||
{ id: 'cache', name: 'Cache', path: 'cacheAugmentation' },
|
||||
{ id: 'batch', name: 'Batch Processing', path: 'batchProcessingAugmentation' },
|
||||
{ id: 'entity-registry', name: 'Entity Registry', path: 'entityRegistryAugmentation' },
|
||||
{ id: 'index', name: 'Index', path: 'indexAugmentation' },
|
||||
{ id: 'metrics', name: 'Metrics', path: 'metricsAugmentation' },
|
||||
{ id: 'monitoring', name: 'Monitoring', path: 'monitoringAugmentation' },
|
||||
{ id: 'connection-pool', name: 'Connection Pool', path: 'connectionPoolAugmentation' },
|
||||
{ id: 'request-deduplicator', name: 'Request Deduplicator', path: 'requestDeduplicatorAugmentation' },
|
||||
{ id: 'api-server', name: 'API Server', path: 'apiServerAugmentation' },
|
||||
{ id: 'neural-import', name: 'Neural Import', path: 'neuralImport' },
|
||||
{ id: 'intelligent-verb-scoring', name: 'Intelligent Verb Scoring', path: 'intelligentVerbScoringAugmentation' },
|
||||
{ id: 'universal-display', name: 'Universal Display', path: 'universalDisplayAugmentation' },
|
||||
// Storage augmentations
|
||||
{ id: 'memory-storage', name: 'Memory Storage', path: 'storageAugmentations', export: 'MemoryStorageAugmentation' },
|
||||
{ id: 'filesystem-storage', name: 'FileSystem Storage', path: 'storageAugmentations', export: 'FileSystemStorageAugmentation' },
|
||||
{ id: 'opfs-storage', name: 'OPFS Storage', path: 'storageAugmentations', export: 'OPFSStorageAugmentation' },
|
||||
{ id: 's3-storage', name: 'S3 Storage', path: 'storageAugmentations', export: 'S3StorageAugmentation' },
|
||||
];
|
||||
for (const aug of builtIn) {
|
||||
this.builtInAugmentations.set(aug.id, {
|
||||
id: aug.id,
|
||||
name: aug.name,
|
||||
source: 'builtin',
|
||||
path: `@soulcraft/brainy/augmentations/${aug.path}`,
|
||||
package: {
|
||||
name: '@soulcraft/brainy',
|
||||
version: 'builtin',
|
||||
description: `Built-in ${aug.name} augmentation`
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Find Brainy installation path
|
||||
*/
|
||||
findBrainyPath() {
|
||||
// Try to find brainy in node_modules
|
||||
const possiblePaths = [
|
||||
join(process.cwd(), 'node_modules', '@soulcraft', 'brainy'),
|
||||
join(process.cwd(), 'node_modules', 'brainy'),
|
||||
join(process.cwd(), '..', 'node_modules', '@soulcraft', 'brainy'),
|
||||
];
|
||||
for (const path of possiblePaths) {
|
||||
if (existsSync(path)) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
// Fallback to current directory
|
||||
return process.cwd();
|
||||
}
|
||||
/**
|
||||
* Discover all augmentations
|
||||
*/
|
||||
async discoverAll() {
|
||||
const augmentations = [];
|
||||
// Add built-in augmentations
|
||||
augmentations.push(...this.builtInAugmentations.values());
|
||||
// Scan node_modules if enabled
|
||||
if (this.options.scanNodeModules) {
|
||||
const installed = await this.scanNodeModules();
|
||||
augmentations.push(...installed);
|
||||
}
|
||||
// Scan local project
|
||||
const local = await this.scanLocalProject();
|
||||
augmentations.push(...local);
|
||||
return augmentations;
|
||||
}
|
||||
/**
|
||||
* Scan node_modules for installed augmentations
|
||||
*/
|
||||
async scanNodeModules() {
|
||||
const augmentations = [];
|
||||
const nodeModulesPath = join(this.options.projectPath, 'node_modules');
|
||||
if (!existsSync(nodeModulesPath)) {
|
||||
return augmentations;
|
||||
}
|
||||
// Scan @brainy/* packages
|
||||
const brainyPath = join(nodeModulesPath, '@brainy');
|
||||
if (existsSync(brainyPath)) {
|
||||
const packages = readdirSync(brainyPath);
|
||||
for (const pkg of packages) {
|
||||
const augmentation = await this.loadPackageAugmentation(join(brainyPath, pkg));
|
||||
if (augmentation) {
|
||||
augmentations.push(augmentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Scan packages with brainy-augmentation keyword
|
||||
const packages = readdirSync(nodeModulesPath);
|
||||
for (const pkg of packages) {
|
||||
if (pkg.startsWith('@') || pkg.startsWith('.'))
|
||||
continue;
|
||||
const pkgPath = join(nodeModulesPath, pkg);
|
||||
const packageJson = this.loadPackageJson(pkgPath);
|
||||
if (packageJson?.keywords?.includes('brainy-augmentation')) {
|
||||
const augmentation = await this.loadPackageAugmentation(pkgPath);
|
||||
if (augmentation) {
|
||||
augmentations.push(augmentation);
|
||||
}
|
||||
}
|
||||
}
|
||||
return augmentations;
|
||||
}
|
||||
/**
|
||||
* Scan local project for augmentations
|
||||
*/
|
||||
async scanLocalProject() {
|
||||
const augmentations = [];
|
||||
// Check for augmentations directory
|
||||
const augPath = join(this.options.projectPath, 'augmentations');
|
||||
if (existsSync(augPath)) {
|
||||
const files = readdirSync(augPath);
|
||||
for (const file of files) {
|
||||
if (file.endsWith('.ts') || file.endsWith('.js')) {
|
||||
const name = file.replace(/\.(ts|js)$/, '');
|
||||
augmentations.push({
|
||||
id: name,
|
||||
name: this.humanizeName(name),
|
||||
source: 'local',
|
||||
path: join(augPath, file)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return augmentations;
|
||||
}
|
||||
/**
|
||||
* Load augmentation from package
|
||||
*/
|
||||
async loadPackageAugmentation(pkgPath) {
|
||||
const packageJson = this.loadPackageJson(pkgPath);
|
||||
if (!packageJson)
|
||||
return null;
|
||||
// Check if it's a brainy augmentation
|
||||
const isBrainyAug = packageJson.keywords?.includes('brainy-augmentation') ||
|
||||
packageJson.brainy?.type === 'augmentation';
|
||||
if (!isBrainyAug)
|
||||
return null;
|
||||
const manifest = packageJson.brainy?.manifest || null;
|
||||
return {
|
||||
id: packageJson.brainy?.id || packageJson.name.replace('@brainy/', ''),
|
||||
name: packageJson.brainy?.name || packageJson.name,
|
||||
source: 'npm',
|
||||
path: pkgPath,
|
||||
manifest,
|
||||
package: {
|
||||
name: packageJson.name,
|
||||
version: packageJson.version,
|
||||
description: packageJson.description
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Load package.json
|
||||
*/
|
||||
loadPackageJson(pkgPath) {
|
||||
const packageJsonPath = join(pkgPath, 'package.json');
|
||||
if (!existsSync(packageJsonPath))
|
||||
return null;
|
||||
try {
|
||||
return JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
||||
}
|
||||
catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Convert name to human-readable format
|
||||
*/
|
||||
humanizeName(name) {
|
||||
return name
|
||||
.replace(/[-_]/g, ' ')
|
||||
.replace(/augmentation/gi, '')
|
||||
.replace(/\b\w/g, l => l.toUpperCase())
|
||||
.trim();
|
||||
}
|
||||
/**
|
||||
* Get built-in augmentations
|
||||
*/
|
||||
getBuiltIn() {
|
||||
return Array.from(this.builtInAugmentations.values());
|
||||
}
|
||||
/**
|
||||
* Get installed augmentations
|
||||
*/
|
||||
getInstalled() {
|
||||
return Array.from(this.installedAugmentations.values());
|
||||
}
|
||||
/**
|
||||
* Check if augmentation is installed
|
||||
*/
|
||||
isInstalled(id) {
|
||||
return this.builtInAugmentations.has(id) ||
|
||||
this.installedAugmentations.has(id);
|
||||
}
|
||||
/**
|
||||
* Get import path for augmentation
|
||||
*/
|
||||
getImportPath(id) {
|
||||
const aug = this.builtInAugmentations.get(id) ||
|
||||
this.installedAugmentations.get(id);
|
||||
return aug?.path || null;
|
||||
}
|
||||
/**
|
||||
* Load augmentation module dynamically
|
||||
*/
|
||||
async loadAugmentation(id) {
|
||||
const path = this.getImportPath(id);
|
||||
if (!path) {
|
||||
throw new Error(`Augmentation ${id} not found`);
|
||||
}
|
||||
// Dynamic import
|
||||
const module = await import(path);
|
||||
return module.default || module;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=localDiscovery.js.map
|
||||
File diff suppressed because one or more lines are too long
97
.recovery-workspace/dist-backup-20250910-141917/augmentations/discovery/runtimeLoader.d.ts
vendored
Normal file
97
.recovery-workspace/dist-backup-20250910-141917/augmentations/discovery/runtimeLoader.d.ts
vendored
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/**
|
||||
* Runtime Augmentation Loader
|
||||
*
|
||||
* Dynamically loads and registers augmentations at runtime
|
||||
* Supports CDN loading for browser environments and npm imports for Node.js
|
||||
*/
|
||||
import { BrainyAugmentation, AugmentationRegistry } from '../brainyAugmentation.js';
|
||||
import { AugmentationManifest } from '../manifest.js';
|
||||
export interface LoaderOptions {
|
||||
cdnUrl?: string;
|
||||
allowUnsafe?: boolean;
|
||||
sandbox?: boolean;
|
||||
timeout?: number;
|
||||
cache?: boolean;
|
||||
}
|
||||
export interface LoadedAugmentation {
|
||||
id: string;
|
||||
instance: BrainyAugmentation;
|
||||
manifest: AugmentationManifest;
|
||||
source: 'cdn' | 'npm' | 'local';
|
||||
loadTime: number;
|
||||
}
|
||||
/**
|
||||
* Runtime Augmentation Loader
|
||||
*
|
||||
* Enables dynamic loading of augmentations from various sources
|
||||
*/
|
||||
export declare class RuntimeAugmentationLoader {
|
||||
private options;
|
||||
private loaded;
|
||||
private cdnCache;
|
||||
private registry?;
|
||||
constructor(options?: LoaderOptions);
|
||||
/**
|
||||
* Set the augmentation registry
|
||||
*/
|
||||
setRegistry(registry: AugmentationRegistry): void;
|
||||
/**
|
||||
* Load augmentation from CDN (browser)
|
||||
*/
|
||||
loadFromCDN(id: string, version?: string, config?: any): Promise<LoadedAugmentation>;
|
||||
/**
|
||||
* Load augmentation from NPM (Node.js)
|
||||
*/
|
||||
loadFromNPM(packageName: string, config?: any): Promise<LoadedAugmentation>;
|
||||
/**
|
||||
* Load augmentation from local file
|
||||
*/
|
||||
loadFromFile(path: string, config?: any): Promise<LoadedAugmentation>;
|
||||
/**
|
||||
* Load multiple augmentations
|
||||
*/
|
||||
loadBatch(augmentations: Array<{
|
||||
source: 'cdn' | 'npm' | 'local';
|
||||
id: string;
|
||||
version?: string;
|
||||
path?: string;
|
||||
config?: any;
|
||||
}>): Promise<LoadedAugmentation[]>;
|
||||
/**
|
||||
* Unload augmentation
|
||||
*/
|
||||
unload(id: string): boolean;
|
||||
/**
|
||||
* Get loaded augmentations
|
||||
*/
|
||||
getLoaded(): LoadedAugmentation[];
|
||||
/**
|
||||
* Check if augmentation is loaded
|
||||
*/
|
||||
isLoaded(id: string): boolean;
|
||||
/**
|
||||
* Get loaded augmentation
|
||||
*/
|
||||
getAugmentation(id: string): BrainyAugmentation | null;
|
||||
/**
|
||||
* Load CDN module (browser-specific)
|
||||
*/
|
||||
private loadCDNModule;
|
||||
/**
|
||||
* Validate augmentation instance
|
||||
*/
|
||||
private isValidAugmentation;
|
||||
/**
|
||||
* Clear all caches
|
||||
*/
|
||||
clearCache(): void;
|
||||
/**
|
||||
* Get load statistics
|
||||
*/
|
||||
getStats(): {
|
||||
loaded: number;
|
||||
totalLoadTime: number;
|
||||
averageLoadTime: number;
|
||||
sources: Record<string, number>;
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,337 @@
|
|||
/**
|
||||
* Runtime Augmentation Loader
|
||||
*
|
||||
* Dynamically loads and registers augmentations at runtime
|
||||
* Supports CDN loading for browser environments and npm imports for Node.js
|
||||
*/
|
||||
/**
|
||||
* Runtime Augmentation Loader
|
||||
*
|
||||
* Enables dynamic loading of augmentations from various sources
|
||||
*/
|
||||
export class RuntimeAugmentationLoader {
|
||||
constructor(options = {}) {
|
||||
this.options = options;
|
||||
this.loaded = new Map();
|
||||
this.cdnCache = new Map();
|
||||
this.options = {
|
||||
cdnUrl: options.cdnUrl || 'https://cdn.soulcraft.com/augmentations',
|
||||
allowUnsafe: options.allowUnsafe || false,
|
||||
sandbox: options.sandbox || true,
|
||||
timeout: options.timeout || 30000,
|
||||
cache: options.cache ?? true
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Set the augmentation registry
|
||||
*/
|
||||
setRegistry(registry) {
|
||||
this.registry = registry;
|
||||
}
|
||||
/**
|
||||
* Load augmentation from CDN (browser)
|
||||
*/
|
||||
async loadFromCDN(id, version = 'latest', config) {
|
||||
// Check if already loaded
|
||||
if (this.loaded.has(id)) {
|
||||
return this.loaded.get(id);
|
||||
}
|
||||
const url = `${this.options.cdnUrl}/${id}@${version}/index.js`;
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
// Load module from CDN
|
||||
const module = await this.loadCDNModule(url);
|
||||
// Extract augmentation class
|
||||
const AugmentationClass = module.default || module[Object.keys(module)[0]];
|
||||
if (!AugmentationClass) {
|
||||
throw new Error(`No augmentation class found in module ${id}`);
|
||||
}
|
||||
// Create instance
|
||||
const instance = new AugmentationClass(config);
|
||||
// Validate it's a proper augmentation
|
||||
if (!this.isValidAugmentation(instance)) {
|
||||
throw new Error(`Invalid augmentation: ${id}`);
|
||||
}
|
||||
// Get manifest
|
||||
const manifest = instance.getManifest ? instance.getManifest() : {
|
||||
id,
|
||||
name: id,
|
||||
version: version,
|
||||
description: `Dynamically loaded ${id}`,
|
||||
category: 'external'
|
||||
};
|
||||
const loaded = {
|
||||
id,
|
||||
instance,
|
||||
manifest,
|
||||
source: 'cdn',
|
||||
loadTime: Date.now() - startTime
|
||||
};
|
||||
// Cache
|
||||
this.loaded.set(id, loaded);
|
||||
// Auto-register if registry is set
|
||||
if (this.registry) {
|
||||
this.registry.register(instance);
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error(`Failed to load augmentation ${id} from CDN: ${error}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Load augmentation from NPM (Node.js)
|
||||
*/
|
||||
async loadFromNPM(packageName, config) {
|
||||
// Check if already loaded
|
||||
const id = packageName.replace('@', '').replace('/', '-');
|
||||
if (this.loaded.has(id)) {
|
||||
return this.loaded.get(id);
|
||||
}
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
// Dynamic import
|
||||
const module = await import(packageName);
|
||||
// Extract augmentation class
|
||||
const AugmentationClass = module.default || module[Object.keys(module)[0]];
|
||||
if (!AugmentationClass) {
|
||||
throw new Error(`No augmentation class found in package ${packageName}`);
|
||||
}
|
||||
// Create instance
|
||||
const instance = new AugmentationClass(config);
|
||||
// Validate
|
||||
if (!this.isValidAugmentation(instance)) {
|
||||
throw new Error(`Invalid augmentation in package: ${packageName}`);
|
||||
}
|
||||
// Get manifest
|
||||
const manifest = instance.getManifest ? instance.getManifest() : {
|
||||
id,
|
||||
name: packageName,
|
||||
version: 'unknown',
|
||||
description: `Loaded from ${packageName}`,
|
||||
category: 'external'
|
||||
};
|
||||
const loaded = {
|
||||
id,
|
||||
instance,
|
||||
manifest,
|
||||
source: 'npm',
|
||||
loadTime: Date.now() - startTime
|
||||
};
|
||||
// Cache
|
||||
this.loaded.set(id, loaded);
|
||||
// Auto-register
|
||||
if (this.registry) {
|
||||
this.registry.register(instance);
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error(`Failed to load augmentation from NPM ${packageName}: ${error}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Load augmentation from local file
|
||||
*/
|
||||
async loadFromFile(path, config) {
|
||||
const startTime = Date.now();
|
||||
try {
|
||||
// Dynamic import
|
||||
const module = await import(path);
|
||||
// Extract augmentation class
|
||||
const AugmentationClass = module.default || module[Object.keys(module)[0]];
|
||||
if (!AugmentationClass) {
|
||||
throw new Error(`No augmentation class found in file ${path}`);
|
||||
}
|
||||
// Create instance
|
||||
const instance = new AugmentationClass(config);
|
||||
// Validate
|
||||
if (!this.isValidAugmentation(instance)) {
|
||||
throw new Error(`Invalid augmentation in file: ${path}`);
|
||||
}
|
||||
// Extract ID from path
|
||||
const id = path.split('/').pop()?.replace(/\.(js|ts)$/, '') || 'unknown';
|
||||
// Get manifest
|
||||
const manifest = instance.getManifest ? instance.getManifest() : {
|
||||
id,
|
||||
name: id,
|
||||
version: 'local',
|
||||
description: `Loaded from ${path}`,
|
||||
category: 'local'
|
||||
};
|
||||
const loaded = {
|
||||
id,
|
||||
instance,
|
||||
manifest,
|
||||
source: 'local',
|
||||
loadTime: Date.now() - startTime
|
||||
};
|
||||
// Cache
|
||||
this.loaded.set(id, loaded);
|
||||
// Auto-register
|
||||
if (this.registry) {
|
||||
this.registry.register(instance);
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
catch (error) {
|
||||
throw new Error(`Failed to load augmentation from file ${path}: ${error}`);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Load multiple augmentations
|
||||
*/
|
||||
async loadBatch(augmentations) {
|
||||
const results = await Promise.allSettled(augmentations.map(aug => {
|
||||
switch (aug.source) {
|
||||
case 'cdn':
|
||||
return this.loadFromCDN(aug.id, aug.version, aug.config);
|
||||
case 'npm':
|
||||
return this.loadFromNPM(aug.id, aug.config);
|
||||
case 'local':
|
||||
return this.loadFromFile(aug.path || aug.id, aug.config);
|
||||
default:
|
||||
return Promise.reject(new Error(`Unknown source: ${aug.source}`));
|
||||
}
|
||||
}));
|
||||
const loaded = [];
|
||||
const errors = [];
|
||||
for (const result of results) {
|
||||
if (result.status === 'fulfilled') {
|
||||
loaded.push(result.value);
|
||||
}
|
||||
else {
|
||||
errors.push(result.reason.message);
|
||||
}
|
||||
}
|
||||
if (errors.length > 0) {
|
||||
console.warn('Some augmentations failed to load:', errors);
|
||||
}
|
||||
return loaded;
|
||||
}
|
||||
/**
|
||||
* Unload augmentation
|
||||
*/
|
||||
unload(id) {
|
||||
const loaded = this.loaded.get(id);
|
||||
if (!loaded)
|
||||
return false;
|
||||
// Shutdown if possible
|
||||
if (loaded.instance.shutdown) {
|
||||
loaded.instance.shutdown();
|
||||
}
|
||||
// Remove from registry if set
|
||||
// Note: Registry doesn't have unregister yet, would need to add
|
||||
// Remove from cache
|
||||
this.loaded.delete(id);
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Get loaded augmentations
|
||||
*/
|
||||
getLoaded() {
|
||||
return Array.from(this.loaded.values());
|
||||
}
|
||||
/**
|
||||
* Check if augmentation is loaded
|
||||
*/
|
||||
isLoaded(id) {
|
||||
return this.loaded.has(id);
|
||||
}
|
||||
/**
|
||||
* Get loaded augmentation
|
||||
*/
|
||||
getAugmentation(id) {
|
||||
return this.loaded.get(id)?.instance || null;
|
||||
}
|
||||
/**
|
||||
* Load CDN module (browser-specific)
|
||||
*/
|
||||
async loadCDNModule(url) {
|
||||
// Check cache
|
||||
if (this.options.cache && this.cdnCache.has(url)) {
|
||||
return this.cdnCache.get(url);
|
||||
}
|
||||
// In browser environment
|
||||
if (typeof window !== 'undefined') {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(() => {
|
||||
reject(new Error(`Timeout loading ${url}`));
|
||||
}, this.options.timeout);
|
||||
// Create script element
|
||||
const script = document.createElement('script');
|
||||
script.type = 'module';
|
||||
script.src = url;
|
||||
// Handle load
|
||||
script.onload = async () => {
|
||||
clearTimeout(timeout);
|
||||
// The module should register itself on window
|
||||
const moduleId = url.split('/').pop()?.split('@')[0];
|
||||
if (moduleId && window[moduleId]) {
|
||||
const module = window[moduleId];
|
||||
// Cache
|
||||
if (this.options.cache) {
|
||||
this.cdnCache.set(url, module);
|
||||
}
|
||||
resolve(module);
|
||||
}
|
||||
else {
|
||||
reject(new Error(`Module not found on window: ${moduleId}`));
|
||||
}
|
||||
};
|
||||
// Handle error
|
||||
script.onerror = () => {
|
||||
clearTimeout(timeout);
|
||||
reject(new Error(`Failed to load script: ${url}`));
|
||||
};
|
||||
// Add to document
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
}
|
||||
else {
|
||||
// In Node.js, use dynamic import
|
||||
const module = await import(url);
|
||||
// Cache
|
||||
if (this.options.cache) {
|
||||
this.cdnCache.set(url, module);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Validate augmentation instance
|
||||
*/
|
||||
isValidAugmentation(instance) {
|
||||
// Check required properties
|
||||
return !!(instance.name &&
|
||||
instance.timing &&
|
||||
instance.operations &&
|
||||
instance.priority !== undefined &&
|
||||
typeof instance.execute === 'function' &&
|
||||
typeof instance.initialize === 'function');
|
||||
}
|
||||
/**
|
||||
* Clear all caches
|
||||
*/
|
||||
clearCache() {
|
||||
this.cdnCache.clear();
|
||||
}
|
||||
/**
|
||||
* Get load statistics
|
||||
*/
|
||||
getStats() {
|
||||
const loaded = Array.from(this.loaded.values());
|
||||
const totalLoadTime = loaded.reduce((sum, aug) => sum + aug.loadTime, 0);
|
||||
const sources = loaded.reduce((acc, aug) => {
|
||||
acc[aug.source] = (acc[aug.source] || 0) + 1;
|
||||
return acc;
|
||||
}, {});
|
||||
return {
|
||||
loaded: loaded.length,
|
||||
totalLoadTime,
|
||||
averageLoadTime: loaded.length > 0 ? totalLoadTime / loaded.length : 0,
|
||||
sources
|
||||
};
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=runtimeLoader.js.map
|
||||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue