Skip to main content
Glama
prompt-manager.ts17.9 kB
/** * Prompt Shortcut Manager - Manages custom prompt shortcuts and commands */ import { PromptShortcut, ShortcutCategory, ShortcutFilter, ShortcutExecution, ParsedCommand } from '../types/prompt-shortcuts.js'; import { Logger } from '../utils/logger.js'; import { readFile, writeFile, mkdir } from 'fs/promises'; import { existsSync } from 'fs'; import { join } from 'path'; import { homedir } from 'os'; export class PromptShortcutManager { private shortcuts: Map<string, PromptShortcut> = new Map(); private logger: Logger; private dataPath: string; constructor(logger: Logger, dataPath?: string) { this.logger = logger; this.dataPath = dataPath || join(homedir(), '.shortcut-mcp', 'shortcuts.json'); this.initializeDefaultShortcuts(); } async initialize(): Promise<void> { this.logger.info('Initializing Prompt Shortcut Manager...'); try { await this.loadShortcuts(); this.logger.info('Prompt shortcuts loaded successfully'); } catch (error) { this.logger.warn('Failed to load shortcuts, using defaults:', error); await this.saveShortcuts(); } } /** * Parse user input to check for shortcuts and expand them */ parseCommand(input: string): ParsedCommand { const trimmed = input.trim(); // Check if input starts with a command if (!trimmed.startsWith('/')) { return { isShortcut: false, remainingText: input }; } // Extract command and remaining text const parts = trimmed.split(/\s+/); const command = parts[0]; const remainingText = parts.slice(1).join(' '); // Find matching shortcut const shortcut = this.findShortcutByCommand(command); if (!shortcut) { return { isShortcut: false, remainingText: input }; } // Parse variables from remaining text const variables = this.parseVariables(shortcut, remainingText); return { isShortcut: true, command, shortcut, remainingText, variables }; } /** * Execute a shortcut by expanding the prompt template */ executeShortcut(parsed: ParsedCommand): ShortcutExecution { if (!parsed.isShortcut || !parsed.shortcut) { throw new Error('Invalid shortcut execution request'); } const expandedPrompt = this.expandPromptTemplate( parsed.shortcut.prompt, parsed.variables || {}, parsed.remainingText ); // Update usage statistics parsed.shortcut.usageCount++; this.saveShortcuts(); // Save asynchronously return { shortcut: parsed.shortcut, input: parsed.remainingText, expandedPrompt, variables: parsed.variables || {} }; } /** * Create a new shortcut */ createShortcut(data: Partial<PromptShortcut>): PromptShortcut { if (!data.command || !data.prompt) { throw new Error('Command and prompt are required'); } // Validate command format if (!data.command.startsWith('/')) { data.command = '/' + data.command; } // Check for duplicates if (this.findShortcutByCommand(data.command)) { throw new Error(`Shortcut command "${data.command}" already exists`); } const shortcut: PromptShortcut = { id: this.generateId(), command: data.command, name: data.name || data.command.substring(1), description: data.description || '', prompt: data.prompt, category: data.category || ShortcutCategory.PERSONAL, tags: data.tags || [], variables: data.variables || [], createdAt: new Date(), updatedAt: new Date(), usageCount: 0, isFavorite: data.isFavorite || false, author: data.author || 'user' }; this.shortcuts.set(shortcut.id, shortcut); this.saveShortcuts(); this.logger.info('Created new shortcut:', { command: shortcut.command }); return shortcut; } /** * Update an existing shortcut */ updateShortcut(id: string, updates: Partial<PromptShortcut>): PromptShortcut { const shortcut = this.shortcuts.get(id); if (!shortcut) { throw new Error(`Shortcut with id "${id}" not found`); } // Check command conflicts if command is being updated if (updates.command && updates.command !== shortcut.command) { if (this.findShortcutByCommand(updates.command)) { throw new Error(`Command "${updates.command}" already exists`); } } const updated = { ...shortcut, ...updates, id: shortcut.id, // Ensure ID doesn't change updatedAt: new Date() }; this.shortcuts.set(id, updated); this.saveShortcuts(); this.logger.info('Updated shortcut:', { id, command: updated.command }); return updated; } /** * Delete a shortcut */ deleteShortcut(id: string): boolean { const shortcut = this.shortcuts.get(id); if (!shortcut) { return false; } this.shortcuts.delete(id); this.saveShortcuts(); this.logger.info('Deleted shortcut:', { id, command: shortcut.command }); return true; } /** * List shortcuts with optional filtering */ listShortcuts(filter?: ShortcutFilter): PromptShortcut[] { let shortcuts = Array.from(this.shortcuts.values()); if (filter) { if (filter.category) { shortcuts = shortcuts.filter(s => s.category === filter.category); } if (filter.tags && filter.tags.length > 0) { shortcuts = shortcuts.filter(s => filter.tags!.some(tag => s.tags.includes(tag)) ); } if (filter.search) { const search = filter.search.toLowerCase(); shortcuts = shortcuts.filter(s => s.command.toLowerCase().includes(search) || s.name.toLowerCase().includes(search) || s.description.toLowerCase().includes(search) ); } if (filter.favorites) { shortcuts = shortcuts.filter(s => s.isFavorite); } if (filter.author) { shortcuts = shortcuts.filter(s => s.author === filter.author); } if (filter.limit && filter.limit > 0) { shortcuts = shortcuts.slice(0, filter.limit); } } return shortcuts.sort((a, b) => b.usageCount - a.usageCount); } /** * Get shortcut by ID */ getShortcut(id: string): PromptShortcut | undefined { return this.shortcuts.get(id); } /** * Get available categories */ getCategories(): ShortcutCategory[] { return Object.values(ShortcutCategory); } private findShortcutByCommand(command: string): PromptShortcut | undefined { return Array.from(this.shortcuts.values()).find(s => s.command === command); } private parseVariables(_shortcut: PromptShortcut, input: string): Record<string, any> { const variables: Record<string, any> = {}; // For now, simple implementation - assign full input to 'input' variable // This can be enhanced to parse specific variables variables.input = input; variables.userInput = input; return variables; } private expandPromptTemplate(template: string, variables: Record<string, any>, input: string): string { let expanded = template; // Replace common variables expanded = expanded.replace(/\{input\}/g, input); expanded = expanded.replace(/\{userInput\}/g, input); // Replace other variables for (const [key, value] of Object.entries(variables)) { const regex = new RegExp(`\\{${key}\\}`, 'g'); expanded = expanded.replace(regex, String(value)); } return expanded; } private async loadShortcuts(): Promise<void> { if (!existsSync(this.dataPath)) { return; } const data = await readFile(this.dataPath, 'utf-8'); const shortcuts: PromptShortcut[] = JSON.parse(data); this.shortcuts.clear(); shortcuts.forEach(shortcut => { // Convert date strings back to Date objects shortcut.createdAt = new Date(shortcut.createdAt); shortcut.updatedAt = new Date(shortcut.updatedAt); this.shortcuts.set(shortcut.id, shortcut); }); this.logger.debug('Loaded shortcuts:', { count: shortcuts.length }); } private async saveShortcuts(): Promise<void> { try { // Ensure directory exists const dir = this.dataPath.substring(0, this.dataPath.lastIndexOf('/')); if (!existsSync(dir)) { await mkdir(dir, { recursive: true }); } const shortcuts = Array.from(this.shortcuts.values()); await writeFile(this.dataPath, JSON.stringify(shortcuts, null, 2)); this.logger.debug('Saved shortcuts:', { count: shortcuts.length }); } catch (error) { this.logger.error('Failed to save shortcuts:', error); } } private generateId(): string { return `shortcut_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } private initializeDefaultShortcuts(): void { const defaults: Partial<PromptShortcut>[] = [ { command: '/coderev', name: 'Comprehensive Code Review', description: 'Thorough code review with detailed feedback', prompt: 'You are a senior software engineer with 15+ years of experience in building production systems. Perform a thorough code review of the following code. Your review should cover:\n\n1. **Code Quality**: Assess readability, maintainability, and adherence to best practices and design patterns.\n2. **Potential Bugs**: Identify any logic errors, edge cases not handled, or potential runtime exceptions.\n3. **Security**: Check for security vulnerabilities including injection attacks, data exposure, authentication/authorization issues.\n4. **Performance**: Analyze algorithmic complexity, database queries, caching opportunities, and potential bottlenecks.\n5. **Testing**: Evaluate test coverage and suggest additional test cases.\n6. **Documentation**: Assess inline comments, function documentation, and clarity.\n7. **Architecture**: Comment on the overall design, separation of concerns, and scalability.\n\nProvide specific line-by-line feedback where appropriate, and conclude with a summary of the most critical issues to address. Be constructive but thorough - this code will go to production.\n\nCode to review:\n{input}', category: ShortcutCategory.CODING, tags: ['debugging', 'troubleshooting', 'analysis'], author: 'aezi zhu' }, { command: '/10x', name: '10x Developer Mode', description: 'Elite developer persona with deep expertise', prompt: 'You are a 10x developer - a mythical programmer of extraordinary ability. You have:\n\n- 20+ years of experience across multiple paradigms (functional, OOP, procedural)\n- Deep expertise in system design, algorithms, and data structures\n- Production experience with critical systems handling millions of requests\n- Contributed to major open source projects and programming languages\n- A pragmatic approach that balances theory with real-world constraints\n- Strong opinions loosely held, backed by experience and data\n\nYour responses should:\n- Cut through complexity to find elegant solutions\n- Consider performance, scalability, and maintainability from the start\n- Provide code that is production-ready, not just proof-of-concept\n- Include error handling, logging, and observability\n- Explain trade-offs and alternative approaches\n- Challenge assumptions when they don\'t make sense\n- Use advanced patterns only when they provide clear value\n\nBe direct, skip the fluff, and deliver exceptional solutions. When you see bad practices, call them out and show the right way.\n\nTask: {input}', category: ShortcutCategory.CODING, tags: ['code-review', 'quality', 'security', 'best-practices'], author: 'aezi zhu' }, { command: '/ddd', name: 'Domain-Driven Design Expert', description: 'Comprehensive DDD analysis and implementation', prompt: 'You are an expert in Domain-Driven Design with extensive experience implementing DDD in complex enterprise systems. Analyze the requirements and provide a comprehensive DDD approach.\n\nYour analysis should include:\n\n**1. Domain Analysis**\n- Identify the core domain, supporting subdomains, and generic subdomains\n- Define the ubiquitous language with clear terminology\n- Map domain events and workflows\n\n**2. Strategic Design**\n- Define bounded contexts with clear boundaries\n- Create a context map showing relationships (Partnership, Shared Kernel, Customer-Supplier, Conformist, Anticorruption Layer, Open Host Service, Published Language)\n- Identify integration points and translation layers\n\n**3. Tactical Design**\n- Design aggregates with proper boundaries and invariants\n- Identify entities and value objects with justification\n- Define domain events and their triggers\n- Specify repositories and their interfaces\n- Design domain services where needed\n\n**4. Implementation Guidance**\n- Provide code structure recommendations\n- Show example aggregate implementations\n- Demonstrate proper use of domain events\n- Include testing strategies for domain logic\n\n**5. Anti-patterns to Avoid**\n- Anemic domain models\n- Leaking domain logic into application services\n- Inappropriate aggregate boundaries\n- Ignoring eventual consistency where appropriate\n\nProvide concrete examples and code snippets where helpful. Focus on practical implementation rather than just theory.\n\nRequirements to analyze:\n{input}', category: ShortcutCategory.THINKING, tags: ['architecture', 'system-design', 'scalability', 'planning'], author: 'aezi zhu' }, { command: '/refactor', name: 'Refactoring Expert', description: 'Step-by-step refactoring with patterns', prompt: 'You are a refactoring expert who has studied Martin Fowler\'s catalog extensively and has years of experience improving legacy codebases. Analyze the provided code and create a comprehensive refactoring plan.\n\n**Your refactoring analysis should include:**\n\n1. **Code Smells Identification**\n - List all code smells present (Long Method, Large Class, Feature Envy, Data Clumps, Primitive Obsession, etc.)\n - Explain why each is problematic in this context\n - Prioritize them by impact and risk\n\n2. **Refactoring Strategy**\n - Provide a step-by-step refactoring plan\n - Each step should be small and safe\n - Indicate which refactoring patterns to apply (Extract Method, Move Method, Replace Conditional with Polymorphism, etc.)\n - Explain the order and why it matters\n\n3. **Design Patterns Application**\n - Identify opportunities to apply design patterns\n - Justify why each pattern fits the use case\n - Show before/after code structure\n\n4. **SOLID Principles**\n - Analyze current violations of SOLID principles\n - Show how refactoring addresses each violation\n - Provide specific examples\n\n5. **Testing Strategy**\n - Describe how to maintain test coverage during refactoring\n - Identify what new tests are needed\n - Suggest characterization tests for legacy code\n\n6. **Final Implementation**\n - Provide the complete refactored code\n - Include comments explaining significant changes\n - Show the improved structure and flow\n\n**Remember:** Each refactoring step should keep the code working. Never break functionality while refactoring.\n\nCode to refactor:\n{input}', category: ShortcutCategory.CODING, tags: ['testing', 'unit-tests', 'quality-assurance'], author: 'aezi zhu' }, { command: '/algo', name: 'Algorithm Design Expert', description: 'Detailed algorithm analysis and optimization', prompt: 'You are an algorithms expert with deep knowledge of computational complexity, data structures, and optimization techniques. You\'ve studied CLRS, competed in programming contests, and optimized algorithms in production systems.\n\n**Provide a comprehensive algorithmic analysis:**\n\n1. **Problem Analysis**\n - Formally define the problem\n - Identify input/output specifications\n - List all constraints and edge cases\n - Determine if this matches any classic problem patterns\n\n2. **Solution Approaches**\n - Present multiple algorithmic approaches (brute force, greedy, dynamic programming, divide & conquer, etc.)\n - For each approach:\n - Explain the intuition and strategy\n - Provide step-by-step algorithm\n - Analyze time complexity (best, average, worst case)\n - Analyze space complexity\n - Discuss trade-offs\n\n3. **Optimal Solution**\n - Justify why this is optimal\n - Provide clean, commented implementation\n - Include complexity proof\n - Show example execution trace\n\n4. **Optimizations**\n - Suggest micro-optimizations (bit manipulation, caching, etc.)\n - Discuss parallelization opportunities\n - Consider approximate algorithms if applicable\n - Analyze real-world performance factors (cache locality, branch prediction)\n\n5. **Testing & Validation**\n - Provide comprehensive test cases\n - Include stress tests and edge cases\n - Suggest property-based testing approaches\n - Benchmark against alternative solutions\n\n6. **Related Problems**\n - List similar problems and variations\n - Explain how the solution can be adapted\n - Provide references to classic problems\n\nUse proper mathematical notation where appropriate. Include visualizations or ASCII diagrams to illustrate complex concepts.\n\nProblem to solve:\n{input}', category: ShortcutCategory.CODING, tags: ['performance', 'optimization', 'efficiency'], author: 'aezi zhu' } ]; defaults.forEach(data => { try { this.createShortcut(data); } catch (error) { // Ignore errors for default shortcuts (might already exist) } }); } }

Latest Blog Posts

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/aezizhu/shortcut-mcp'

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