UNPKG

claude-flow

Version:

Ruflo - Enterprise AI agent orchestration for Claude Code. Deploy 60+ specialized agents in coordinated swarms with self-learning, fault-tolerant consensus, vector memory, and MCP integration

294 lines 11 kB
/** * Pattern Publish Service * Publish and contribute patterns to decentralized registry */ import * as fs from 'fs'; import * as crypto from 'crypto'; import { DEFAULT_STORE_CONFIG, generatePatternId } from './registry.js'; import { anonymizeCFP } from '../anonymization/index.js'; import { uploadToIPFS, pinContent } from '../ipfs/upload.js'; /** * Pattern Publisher * Handles publishing patterns to IPFS and registry */ export class PatternPublisher { config; constructor(config = {}) { this.config = { ...DEFAULT_STORE_CONFIG, ...config }; } /** * Publish a pattern to IPFS and registry */ async publishPattern(cfp, options) { console.log(`[Publish] Starting publish: ${options.name}`); try { // Step 1: Anonymize if needed const anonymized = anonymizeCFP(cfp, options.anonymize); console.log(`[Publish] Anonymization level: ${options.anonymize}`); // Step 2: Serialize content const content = JSON.stringify(anonymized, null, 2); const contentBuffer = Buffer.from(content); // Step 3: Calculate checksum const checksum = crypto .createHash('sha256') .update(contentBuffer) .digest('hex'); // Step 4: Sign if private key provided let signature; let publicKey; if (options.privateKeyPath && fs.existsSync(options.privateKeyPath)) { const signResult = this.signContent(contentBuffer, options.privateKeyPath); signature = signResult.signature; publicKey = signResult.publicKey; console.log(`[Publish] Content signed`); } // Get author info early (needed for GCS metadata and pattern entry) const author = this.getAuthor(); // Step 5: Upload to IPFS or GCS let uploadCid; let gatewayUrl; // Check if GCS is configured try { const { hasGCSCredentials, uploadToGCS } = await import('../storage/gcs.js'); if (hasGCSCredentials()) { console.log(`[Publish] Uploading to Google Cloud Storage...`); const gcsResult = await uploadToGCS(contentBuffer, { name: `${options.name}.cfp.json`, metadata: { checksum, author: author.id, version: cfp.version, }, }); if (gcsResult.success) { uploadCid = gcsResult.uri; // Use GCS URI as CID gatewayUrl = gcsResult.publicUrl; console.log(`[Publish] Uploaded to GCS: ${gcsResult.uri}`); } else { throw new Error('GCS upload failed'); } } else { throw new Error('GCS not configured'); } } catch { // Fallback to IPFS console.log(`[Publish] Uploading to IPFS...`); const uploadResult = await uploadToIPFS(contentBuffer, { name: `${options.name}.cfp.json`, pin: true, }); if (!uploadResult.cid) { return { success: false, patternId: '', cid: '', registryCid: '', gatewayUrl: '', message: 'Failed to upload to IPFS (no IPFS credentials configured)', }; } uploadCid = uploadResult.cid; gatewayUrl = `${this.config.gateway}/ipfs/${uploadResult.cid}`; console.log(`[Publish] Uploaded to IPFS: ${uploadResult.cid}`); // Pin content await pinContent(uploadResult.cid); } // Step 6: Create pattern entry const patternId = generatePatternId(options.name); const patternEntry = { id: patternId, name: options.name, displayName: options.displayName, description: options.description, version: cfp.version, cid: uploadCid, size: contentBuffer.length, checksum, author, license: options.license, categories: options.categories, tags: options.tags, language: options.language, framework: options.framework, downloads: 0, rating: 0, ratingCount: 0, lastUpdated: new Date().toISOString(), createdAt: new Date().toISOString(), minClaudeFlowVersion: '3.0.0', verified: author.verified, trustLevel: author.verified ? 'verified' : 'community', signature, publicKey, }; // Step 7: Add to registry (in production: submit to registry maintainers) console.log(`[Publish] Pattern entry created: ${patternId}`); return { success: true, patternId, cid: uploadCid, registryCid: '', // Would be updated after registry update gatewayUrl, message: `Pattern '${options.displayName}' published successfully!`, }; } catch (error) { console.error(`[Publish] Failed:`, error); return { success: false, patternId: '', cid: '', registryCid: '', gatewayUrl: '', message: `Publish failed: ${error}`, }; } } /** * Sign content with private key */ signContent(content, privateKeyPath) { // In production: Use actual Ed25519 signing // For demo: Generate mock signature const privateKey = fs.readFileSync(privateKeyPath, 'utf-8').trim(); const signature = crypto .createHmac('sha256', privateKey) .update(content) .digest('hex'); const publicKey = 'ed25519:' + crypto.createHash('sha256').update(privateKey).digest('hex').slice(0, 32); return { signature: `ed25519:${signature}`, publicKey, }; } /** * Get current author info */ getAuthor() { if (this.config.authorId) { return { id: this.config.authorId, displayName: this.config.authorId, verified: false, patterns: 0, totalDownloads: 0, }; } // Anonymous author return { id: `anon-${crypto.randomBytes(8).toString('hex')}`, verified: false, patterns: 0, totalDownloads: 0, }; } /** * Validate pattern before publish */ validateForPublish(cfp, options) { const errors = []; // Check required fields if (!options.name || options.name.length < 3) { errors.push('Name must be at least 3 characters'); } if (!options.displayName || options.displayName.length < 3) { errors.push('Display name must be at least 3 characters'); } if (!options.description || options.description.length < 20) { errors.push('Description must be at least 20 characters'); } if (!options.categories || options.categories.length === 0) { errors.push('At least one category is required'); } if (!options.tags || options.tags.length < 3) { errors.push('At least 3 tags are required'); } // Check valid license const validLicenses = ['MIT', 'Apache-2.0', 'GPL-3.0', 'BSD-3-Clause', 'CC-BY-4.0', 'Unlicense']; if (!validLicenses.includes(options.license)) { errors.push(`License must be one of: ${validLicenses.join(', ')}`); } // Check pattern content if (cfp.magic !== 'CFP1') { errors.push('Invalid CFP format (missing magic header)'); } const totalPatterns = cfp.statistics.totalPatterns; if (totalPatterns === 0) { errors.push('Pattern must contain at least one pattern'); } return errors; } /** * Create publish preview */ createPreview(cfp, options) { return { name: options.name, displayName: options.displayName, description: options.description, categories: options.categories, tags: options.tags, license: options.license, language: options.language, framework: options.framework, anonymization: options.anonymize, statistics: cfp.statistics, estimatedSize: JSON.stringify(cfp).length, }; } } /** * Submit a contribution to the registry */ export async function submitContribution(request) { console.log(`[Contribute] Submitting contribution: ${request.name}`); // In production: Submit to registry governance system // For demo: Generate mock submission ID const submissionId = `contrib-${crypto.randomBytes(8).toString('hex')}`; console.log(`[Contribute] Submission ID: ${submissionId}`); console.log(`[Contribute] Pattern CID: ${request.patternCid}`); console.log(`[Contribute] Author: ${request.authorId}`); return { success: true, submissionId, message: `Contribution submitted for review. Track status with ID: ${submissionId}`, }; } /** * Check contribution status */ export async function checkContributionStatus(submissionId) { // In production: Query registry governance system // For demo: Return mock status return { status: 'pending', message: 'Your contribution is pending review', }; } /** * Create publisher with default config */ export function createPublisher(config) { return new PatternPublisher(config); } /** * Quick publish helper */ export async function quickPublish(cfp, name, description, tags, config) { const publisher = new PatternPublisher(config); const options = { name, displayName: name.replace(/-/g, ' ').replace(/\b\w/g, c => c.toUpperCase()), description, categories: ['custom'], tags, license: 'MIT', anonymize: 'standard', }; return publisher.publishPattern(cfp, options); } //# sourceMappingURL=publish.js.map