UNPKG

@stackmemoryai/stackmemory

Version:

Lossless, project-scoped memory for AI coding tools. Durable context across sessions with 56 MCP tools, FTS5 search, conductor orchestrator, loop/watch monitoring, snapshot capture, pre-flight overlap checks, Claude/Codex/OpenCode wrappers, Linear sync, a

133 lines (132 loc) 3.44 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { logger } from "../../core/monitoring/logger.js"; class BaseVerifier { config; retryCount = /* @__PURE__ */ new Map(); constructor(config) { this.config = config; } /** * Extract most relevant error messages (Spotify pattern) */ extractRelevantErrors(output, patterns) { const errors = []; const lines = output.split("\n"); for (const line of lines) { for (const pattern of patterns) { const match = line.match(pattern); if (match) { errors.push(match[0]); break; } } } return errors.slice(0, 5); } /** * Generate incremental feedback */ generateFeedback(errors, context) { if (errors.length === 0) { return `${this.config.name} verification passed`; } const prefix = context.filePath ? `In ${context.filePath}: ` : ""; const errorList = errors.map((e) => ` - ${e}`).join("\n"); return `${prefix}${this.config.name} found ${errors.length} issue(s): ${errorList}`; } /** * Retry logic for transient failures */ async withRetry(operation, key) { const maxRetries = this.config.maxRetries || 0; const currentRetries = this.retryCount.get(key) || 0; try { const result = await operation(); this.retryCount.delete(key); return result; } catch (error) { if (currentRetries < maxRetries) { this.retryCount.set(key, currentRetries + 1); logger.warn(`Retrying ${this.config.name} verification`, { attempt: currentRetries + 1, maxRetries, error: error instanceof Error ? error.message : String(error) }); await this.delay(Math.pow(2, currentRetries) * 1e3); return this.withRetry(operation, key); } this.retryCount.delete(key); throw error; } } /** * Apply timeout to verification */ async withTimeout(operation) { if (!this.config.timeout) { return operation(); } return Promise.race([ operation(), new Promise( (_, reject) => setTimeout( () => reject( new Error( `${this.config.name} timeout after ${this.config.timeout}ms` ) ), this.config.timeout ) ) ]); } /** * Helper to create a standard result */ createResult(passed, message, severity = "info", details, autoFix) { return { verifierId: this.config.id, verifierType: this.config.type, passed, message, severity, timestamp: /* @__PURE__ */ new Date(), details: details || void 0, autoFix: autoFix || void 0 }; } /** * Delay helper for retries */ delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } /** * Get verifier configuration */ getConfig() { return { ...this.config }; } /** * Check if verifier should stop execution on error */ shouldStopOnError() { return this.config.stopOnError; } /** * Update verifier configuration */ updateConfig(updates) { this.config = { ...this.config, ...updates }; logger.info(`Updated ${this.config.name} configuration`, { updates }); } } export { BaseVerifier };