Skip to main content
Glama

mcp-adr-analysis-server

by tosin2013
system-card-manager.ts13.8 kB
import { promises as fs } from 'fs'; import * as path from 'path'; import * as yaml from 'js-yaml'; import { EnhancedLogger } from './enhanced-logging.js'; /** * Platform information detected during bootstrap */ export interface PlatformInfo { type: 'kubernetes' | 'openshift' | 'docker-compose' | 'systemd' | 'unknown'; version?: string; detectionConfidence: number; namespace?: string; clusterInfo?: Record<string, any>; } /** * Bootstrap context references */ export interface BootstrapContext { adrPath?: string; contextPath?: string; validatedPatternId?: string; bootstrapId: string; initiatedBy?: string; } /** * Individual resource record */ export interface ResourceRecord { type: | 'namespace' | 'deployment' | 'service' | 'configmap' | 'secret' | 'ingress' | 'statefulset' | 'pod' | 'persistentvolumeclaim' | 'custom'; name: string; namespace?: string; uid?: string; labels?: Record<string, string>; annotations?: Record<string, string>; metadata?: Record<string, any>; created: string; createdByTask: string; createdByPhase?: string; cleanupCommand: string; cleanupOrder?: number; } /** * Cleanup strategy configuration */ export interface CleanupStrategy { strategy: 'label-based' | 'explicit' | 'namespace-cascade'; labelSelector?: Record<string, string>; dryRun?: boolean; phases: CleanupPhase[]; } /** * Individual cleanup phase */ export interface CleanupPhase { order: number; name: string; description?: string; commands: CleanupCommand[]; canParallelize?: boolean; estimatedDuration?: string; } /** * Individual cleanup command */ export interface CleanupCommand { description: string; command: string; expectedExitCode?: number; continueOnError?: boolean; verificationCommand?: string; } /** * State snapshot for rollback capability */ export interface StateSnapshot { timestamp: string; beforeAction: string; resourceCount: number; checksum: string; } /** * Complete SystemCard structure */ export interface SystemCard { version: string; systemId: string; created: string; lastUpdated?: string; platform: PlatformInfo; bootstrapContext: BootstrapContext; resources: { namespaces?: ResourceRecord[]; deployments?: ResourceRecord[]; services?: ResourceRecord[]; configmaps?: ResourceRecord[]; secrets?: ResourceRecord[]; ingresses?: ResourceRecord[]; statefulsets?: ResourceRecord[]; pods?: ResourceRecord[]; persistentvolumeclaims?: ResourceRecord[]; custom?: ResourceRecord[]; }; cleanup: CleanupStrategy; snapshots?: StateSnapshot[]; metadata?: { tags?: string[]; description?: string; owner?: string; }; } /** * Options for SystemCard initialization */ export interface SystemCardInitOptions { systemId: string; created: string; platform: PlatformInfo; bootstrapContext: BootstrapContext; metadata?: { tags?: string[]; description?: string; owner?: string; }; } /** * Manages SystemCard creation, updates, and persistence */ export class SystemCardManager { private systemCardPath: string; private logger: EnhancedLogger; private currentCard: SystemCard | null = null; constructor(projectPath: string) { this.systemCardPath = path.join(projectPath, 'systemcard.yaml'); this.logger = new EnhancedLogger(); } /** * Initialize a new SystemCard */ async initialize(options: SystemCardInitOptions): Promise<void> { try { this.currentCard = { version: '1.0', systemId: options.systemId, created: options.created, lastUpdated: options.created, platform: options.platform, bootstrapContext: options.bootstrapContext, resources: {}, cleanup: { strategy: 'label-based', labelSelector: { 'managed-by': 'mcp-adr-server', 'bootstrap-id': options.bootstrapContext.bootstrapId, }, phases: [], }, ...(options.metadata && { metadata: options.metadata }), }; await this.save(); this.logger.info(`SystemCard initialized: ${this.systemCardPath}`, 'SystemCardManager'); } catch (error) { this.logger.error('Failed to initialize SystemCard', 'SystemCardManager', error as Error); throw error; } } /** * Load existing SystemCard from disk */ async load(): Promise<SystemCard | null> { try { const content = await fs.readFile(this.systemCardPath, 'utf-8'); this.currentCard = yaml.load(content) as SystemCard; this.logger.info('SystemCard loaded successfully', 'SystemCardManager'); return this.currentCard; } catch (error) { if ((error as NodeJS.ErrnoException).code === 'ENOENT') { this.logger.warn('SystemCard not found', 'SystemCardManager'); return null; } this.logger.error('Failed to load SystemCard', 'SystemCardManager', error as Error); throw error; } } /** * Save current SystemCard to disk */ async save(): Promise<void> { if (!this.currentCard) { throw new Error('No SystemCard initialized. Call initialize() first.'); } try { this.currentCard.lastUpdated = new Date().toISOString(); const yamlContent = yaml.dump(this.currentCard, { indent: 2, lineWidth: -1, noRefs: true, }); await fs.writeFile(this.systemCardPath, yamlContent, 'utf-8'); this.logger.info('SystemCard saved successfully', 'SystemCardManager'); } catch (error) { this.logger.error('Failed to save SystemCard', 'SystemCardManager', error as Error); throw error; } } /** * Add resources to the SystemCard */ async addResources( resources: ResourceRecord[], context?: { phase?: string; taskId?: string } ): Promise<void> { if (!this.currentCard) { throw new Error('No SystemCard loaded. Call load() or initialize() first.'); } try { for (const resource of resources) { // Add phase/task context if provided if (context?.phase) { resource.createdByPhase = context.phase; } if (context?.taskId && !resource.createdByTask) { resource.createdByTask = context.taskId; } // Categorize by type const category = this.getResourceCategory(resource.type); if (!this.currentCard.resources[category]) { this.currentCard.resources[category] = []; } // Check for duplicates const exists = this.currentCard.resources[category]!.some( r => r.name === resource.name && r.namespace === resource.namespace ); if (!exists) { this.currentCard.resources[category]!.push(resource); this.logger.info( `Added resource: ${resource.type}/${resource.name}`, 'SystemCardManager' ); } } await this.save(); } catch (error) { this.logger.error('Failed to add resources', 'SystemCardManager', error as Error); throw error; } } /** * Remove a resource from the SystemCard */ async removeResource(type: string, name: string, namespace?: string): Promise<void> { if (!this.currentCard) { throw new Error('No SystemCard loaded.'); } try { const category = this.getResourceCategory(type); const resources = this.currentCard.resources[category]; if (resources) { const index = resources.findIndex( r => r.name === name && (namespace ? r.namespace === namespace : true) ); if (index !== -1) { resources.splice(index, 1); this.logger.info(`Removed resource: ${type}/${name}`, 'SystemCardManager'); await this.save(); } } } catch (error) { this.logger.error('Failed to remove resource', 'SystemCardManager', error as Error); throw error; } } /** * Generate cleanup phases from current resources * Resources are ordered in reverse of typical deployment order */ async generateCleanupPhases(): Promise<CleanupPhase[]> { if (!this.currentCard) { throw new Error('No SystemCard loaded.'); } try { const phases: CleanupPhase[] = []; let order = 1; // Order of cleanup (reverse of typical deployment) const cleanupOrder = [ 'ingresses', 'services', 'deployments', 'statefulsets', 'pods', 'configmaps', 'secrets', 'persistentvolumeclaims', 'namespaces', 'custom', ]; for (const category of cleanupOrder) { const resources = this.currentCard.resources[category as keyof typeof this.currentCard.resources]; if (resources && resources.length > 0) { const phase: CleanupPhase = { order: order++, name: `Delete ${category}`, description: `Remove all ${category} created during bootstrap`, commands: resources.map(r => ({ description: `Delete ${r.type} ${r.name}`, command: r.cleanupCommand, expectedExitCode: 0, continueOnError: false, })), canParallelize: true, estimatedDuration: `${resources.length * 2}-${resources.length * 5} seconds`, }; phases.push(phase); } } // Update SystemCard with generated cleanup phases this.currentCard.cleanup.phases = phases; await this.save(); this.logger.info(`Generated ${phases.length} cleanup phases`, 'SystemCardManager'); return phases; } catch (error) { this.logger.error('Failed to generate cleanup phases', 'SystemCardManager', error as Error); throw error; } } /** * Create a state snapshot for rollback capability */ async createSnapshot(beforeAction: string): Promise<StateSnapshot> { if (!this.currentCard) { throw new Error('No SystemCard loaded.'); } try { const resourceCount = Object.values(this.currentCard.resources) .filter(arr => Array.isArray(arr)) .reduce((sum, arr) => sum + arr.length, 0); const checksum = this.calculateChecksum(this.currentCard); const snapshot: StateSnapshot = { timestamp: new Date().toISOString(), beforeAction, resourceCount, checksum, }; if (!this.currentCard.snapshots) { this.currentCard.snapshots = []; } this.currentCard.snapshots.push(snapshot); await this.save(); this.logger.info(`Snapshot created: ${beforeAction}`, 'SystemCardManager'); return snapshot; } catch (error) { this.logger.error('Failed to create snapshot', 'SystemCardManager', error as Error); throw error; } } /** * Get all resources of a specific type */ getResourcesByType(type: string): ResourceRecord[] { if (!this.currentCard) { return []; } const category = this.getResourceCategory(type); return this.currentCard.resources[category] || []; } /** * Get all resources created by a specific task */ getResourcesByTask(taskId: string): ResourceRecord[] { if (!this.currentCard) { return []; } const allResources: ResourceRecord[] = []; for (const category of Object.keys(this.currentCard.resources)) { const resources = this.currentCard.resources[category as keyof typeof this.currentCard.resources]; if (resources) { allResources.push(...resources.filter(r => r.createdByTask === taskId)); } } return allResources; } /** * Get total count of all resources */ getResourceCount(): number { if (!this.currentCard) { return 0; } return Object.values(this.currentCard.resources) .filter(arr => Array.isArray(arr)) .reduce((sum, arr) => sum + arr.length, 0); } /** * Get current SystemCard */ getCurrentCard(): SystemCard | null { return this.currentCard; } /** * Check if SystemCard exists on disk */ async exists(): Promise<boolean> { try { await fs.access(this.systemCardPath); return true; } catch { return false; } } /** * Delete SystemCard file from disk */ async delete(): Promise<void> { try { await fs.unlink(this.systemCardPath); this.currentCard = null; this.logger.info('SystemCard deleted', 'SystemCardManager'); } catch (error) { if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { this.logger.error('Failed to delete SystemCard', 'SystemCardManager', error as Error); throw error; } } } /** * Map resource type to storage category */ private getResourceCategory(type: string): keyof SystemCard['resources'] { const typeMap: Record<string, keyof SystemCard['resources']> = { namespace: 'namespaces', deployment: 'deployments', service: 'services', configmap: 'configmaps', secret: 'secrets', ingress: 'ingresses', statefulset: 'statefulsets', pod: 'pods', persistentvolumeclaim: 'persistentvolumeclaims', custom: 'custom', }; return typeMap[type] || 'custom'; } /** * Calculate checksum for state verification */ private calculateChecksum(card: SystemCard): string { const contentString = JSON.stringify(card.resources); // Simple hash function (in production, use crypto.createHash) let hash = 0; for (let i = 0; i < contentString.length; i++) { const char = contentString.charCodeAt(i); hash = (hash << 5) - hash + char; hash = hash & hash; // Convert to 32-bit integer } return hash.toString(16); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/tosin2013/mcp-adr-analysis-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server