UNPKG

@endlessblink/like-i-said-v2

Version:

Task Management & Memory for Claude - Track tasks, remember context, and maintain continuity across sessions with 27 powerful tools. Works with Claude Desktop and Claude Code.

411 lines (352 loc) 15.7 kB
/** * Memory Quality Standards and Validation * Defines specific quality criteria and standards for memory titles and descriptions */ class MemoryQualityStandards { constructor() { this.titleStandards = this.defineTitleStandards(); this.descriptionStandards = this.defineDescriptionStandards(); } /** * Define strict title quality standards */ defineTitleStandards() { return { // Length requirements minLength: 15, maxLength: 80, optimalLength: { min: 20, max: 60 }, // Required characteristics mustHave: { specificAction: true, // Must indicate what was done (fix, add, create, etc.) specificSubject: true, // Must specify what component/feature noGenericWords: true, // No "dashboard improvements", "session", etc. noTimestamps: true, // No dates in titles noTruncation: true, // No "..." or cut-off words properCapitalization: true // Title case or sentence case }, // Forbidden patterns forbiddenPatterns: [ /^dashboard improvements?/i, /session\s*\(/i, /\(\s*\w+\s+\d{1,2},?\s+\d{4}\s*\)/, // (June 16, 2025) /^(major|complete|comprehensive)\s+/i, /^(session|meeting|call|discussion)/i, /^(status|update|progress)\s+/i, /\.\.\./, /^-----/, /^id-\d+/, /\$\(date/ ], // Generic words that make titles weak weakWords: [ 'improvements', 'session', 'update', 'status', 'progress', 'changes', 'modifications', 'enhancements', 'work', 'stuff', 'things', 'various', 'multiple', 'general' ], // Strong action words that make good titles strongActions: [ 'implement', 'fix', 'add', 'create', 'configure', 'optimize', 'refactor', 'integrate', 'migrate', 'deploy', 'automate', 'establish', 'resolve', 'develop', 'design', 'build' ], // Technical specificity requirements specificity: { requiresComponent: true, // Must mention specific component requiresContext: true, // Must provide context avoidVague: true // Avoid vague descriptions } }; } /** * Define strict description quality standards */ defineDescriptionStandards() { return { // Length requirements minLength: 50, maxLength: 300, optimalLength: { min: 80, max: 200 }, // Structure requirements structure: { requiresContext: true, // What was the problem/goal requiresActions: true, // What specific actions were taken requiresOutcome: true, // What was achieved/result requiresBulletPoints: false, // Optional but preferred for lists requiresCodeBlocks: false // When relevant }, // Content quality content: { specificDetails: true, // Must have specific technical details noGenericPhrases: true, // Avoid generic descriptions properTechnicalTerms: true, // Use correct technical terminology actionableInformation: true, // Information others can act on contextualRelevance: true // Relevant to the project/system }, // Forbidden phrases forbiddenPhrases: [ 'various things', 'different stuff', 'multiple improvements', 'general enhancements', 'overall progress', 'status update', 'session complete', 'work done', 'fixes applied' ], // Required elements for technical content technicalRequirements: { fileNames: true, // Mention specific files modified technologies: true, // Mention specific technologies used problemStatement: true, // Clear problem description solutionDetails: true // Specific solution implementation } }; } /** * Validate title against quality standards */ validateTitle(title) { const validation = { isValid: true, score: 100, violations: [], suggestions: [] }; if (!title || typeof title !== 'string') { validation.isValid = false; validation.score = 0; validation.violations.push('Title is missing or invalid'); return validation; } const cleanTitle = title.trim(); // Length validation if (cleanTitle.length < this.titleStandards.minLength) { validation.violations.push(`Title too short (${cleanTitle.length} < ${this.titleStandards.minLength})`); validation.score -= 20; } if (cleanTitle.length > this.titleStandards.maxLength) { validation.violations.push(`Title too long (${cleanTitle.length} > ${this.titleStandards.maxLength})`); validation.score -= 15; } // Forbidden patterns for (const pattern of this.titleStandards.forbiddenPatterns) { if (pattern.test(cleanTitle)) { validation.violations.push(`Contains forbidden pattern: ${pattern.source}`); validation.score -= 25; } } // Weak words check const titleLower = cleanTitle.toLowerCase(); const foundWeakWords = this.titleStandards.weakWords.filter(word => titleLower.includes(word) ); if (foundWeakWords.length > 0) { validation.violations.push(`Contains weak words: ${foundWeakWords.join(', ')}`); validation.score -= 15 * foundWeakWords.length; } // Strong action words check const hasStrongAction = this.titleStandards.strongActions.some(action => titleLower.includes(action) ); if (!hasStrongAction) { validation.violations.push('Missing strong action word'); validation.score -= 20; validation.suggestions.push(`Consider starting with: ${this.titleStandards.strongActions.slice(0, 5).join(', ')}`); } // Specificity checks if (this.isVagueTitle(cleanTitle)) { validation.violations.push('Title is too vague or generic'); validation.score -= 25; } if (validation.score < 70) { validation.isValid = false; } return validation; } /** * Validate description against quality standards */ validateDescription(description, title = '') { const validation = { isValid: true, score: 100, violations: [], suggestions: [] }; if (!description || typeof description !== 'string') { validation.isValid = false; validation.score = 0; validation.violations.push('Description is missing or invalid'); return validation; } const cleanDesc = description.trim(); // Length validation if (cleanDesc.length < this.descriptionStandards.minLength) { validation.violations.push(`Description too short (${cleanDesc.length} < ${this.descriptionStandards.minLength})`); validation.score -= 25; } if (cleanDesc.length > this.descriptionStandards.maxLength) { validation.violations.push(`Description too long (${cleanDesc.length} > ${this.descriptionStandards.maxLength})`); validation.score -= 15; } // Forbidden phrases const descLower = cleanDesc.toLowerCase(); for (const phrase of this.descriptionStandards.forbiddenPhrases) { if (descLower.includes(phrase)) { validation.violations.push(`Contains forbidden phrase: "${phrase}"`); validation.score -= 20; } } // Structure validation if (!this.hasProperStructure(cleanDesc)) { validation.violations.push('Poor structure - lacks context, actions, or outcome'); validation.score -= 20; } // Technical content validation if (!this.hasTechnicalSpecificity(cleanDesc)) { validation.violations.push('Lacks technical specificity'); validation.score -= 25; validation.suggestions.push('Add specific file names, technologies, or implementation details'); } // Redundancy with title if (this.isRedundantWithTitle(cleanDesc, title)) { validation.violations.push('Description is too similar to title'); validation.score -= 15; } if (validation.score < 70) { validation.isValid = false; } return validation; } /** * Check if title is vague */ isVagueTitle(title) { const vaguePatterns = [ /^(dashboard|system|application|project)\s+(work|updates?|changes?|improvements?)/i, /^(major|minor|general|overall|complete)\s+/i, /^(session|meeting|call|discussion)\s+/i, /^(status|progress|update)\s+(on|for|of)/i ]; return vaguePatterns.some(pattern => pattern.test(title)); } /** * Check if description has proper structure */ hasProperStructure(description) { // Should have some indication of problem/context, action, and result const hasContext = /\b(problem|issue|needed|required|goal|objective)\b/i.test(description); const hasAction = /\b(implemented|fixed|added|created|configured|modified|updated)\b/i.test(description); const hasOutcome = /\b(now|result|completed|working|resolved|achieved)\b/i.test(description); return hasContext || hasAction || hasOutcome; } /** * Check if description has technical specificity */ hasTechnicalSpecificity(description) { // Should mention files, technologies, or specific implementations const hasFiles = /\.(js|ts|tsx|css|json|md|py|java|cpp)\b/i.test(description); const hasTech = /\b(react|node|express|api|database|docker|git|npm|webpack)\b/i.test(description); const hasSpecifics = /\b(function|component|endpoint|route|query|method|class)\b/i.test(description); return hasFiles || hasTech || hasSpecifics; } /** * Check if description is redundant with title */ isRedundantWithTitle(description, title) { if (!title) return false; const titleWords = title.toLowerCase().split(/\s+/); const descWords = description.toLowerCase().split(/\s+/).slice(0, 10); // First 10 words const overlap = titleWords.filter(word => word.length > 3 && descWords.includes(word) ); return overlap.length > titleWords.length * 0.6; // More than 60% overlap } /** * Generate improvement suggestions for title */ generateTitleSuggestions(title, content = '') { const suggestions = []; if (!title || this.isVagueTitle(title)) { // Extract potential title from content const extractedTitle = this.extractTitleFromContent(content); if (extractedTitle) { suggestions.push(`Suggested title: "${extractedTitle}"`); } } // Generic improvement suggestions suggestions.push('Use specific action words: implement, fix, add, create, configure'); suggestions.push('Mention specific component/feature being modified'); suggestions.push('Avoid generic words like "improvements", "session", "updates"'); suggestions.push('Remove dates and timestamps from title'); return suggestions; } /** * Extract a better title from content */ extractTitleFromContent(content) { if (!content) return null; // Look for headers const headerMatch = content.match(/^#+\s+(.+)$/m); if (headerMatch) { const header = headerMatch[1].trim(); if (header.length >= 15 && header.length <= 80) { return header; } } // Look for first meaningful sentence with action const sentences = content.split(/[.!?]+/).filter(s => s.trim().length > 10); for (const sentence of sentences.slice(0, 3)) { const trimmed = sentence.trim(); const hasAction = this.titleStandards.strongActions.some(action => trimmed.toLowerCase().includes(action) ); if (hasAction && trimmed.length >= 15 && trimmed.length <= 80) { return this.improveTitle(trimmed); } } return null; } /** * Improve a title by applying standards */ improveTitle(rawTitle) { let improved = rawTitle.trim(); // Remove common prefixes improved = improved.replace(/^(this|that|here|we|i)\s+/i, ''); improved = improved.replace(/^(is|are|was|were|will|would|should|could)\s+/i, ''); // Capitalize properly improved = improved.charAt(0).toUpperCase() + improved.slice(1); // Remove timestamps and sessions improved = improved.replace(/\s*\([^)]*\d{4}[^)]*\)/g, ''); improved = improved.replace(/\s*session\s*$/i, ''); return improved; } /** * Get overall quality standards summary */ getStandardsSummary() { return { title: { length: `${this.titleStandards.minLength}-${this.titleStandards.maxLength} chars`, required: 'Specific action + component/feature', forbidden: 'Generic words, dates, truncation', examples: { good: [ 'Implement WebSocket real-time memory synchronization', 'Fix React Flow node positioning calculation bug', 'Add Docker environment configuration for dashboard' ], bad: [ 'Dashboard Improvements Session', 'Major UI/UX Fixes Completed', 'WSL Configuration Status Update' ] } }, description: { length: `${this.descriptionStandards.minLength}-${this.descriptionStandards.maxLength} chars`, required: 'Context + Actions + Technical details', structure: 'Problem → Solution → Result', forbidden: 'Generic phrases, redundancy with title' } }; } } module.exports = { MemoryQualityStandards };