UNPKG

@stackmemoryai/stackmemory

Version:

Project-scoped memory for AI coding tools. Durable context across sessions with MCP integration, frames, smart retrieval, Claude Code skills, and automatic hooks.

322 lines (321 loc) 9.62 kB
import { fileURLToPath as __fileURLToPath } from 'url'; import { dirname as __pathDirname } from 'path'; const __filename = __fileURLToPath(import.meta.url); const __dirname = __pathDirname(__filename); import { FrameType, FrameStatus } from "./query-parser.js"; class QueryTemplates { templates = [ { name: "daily-standup", description: "Get work done by a person today for standup", pattern: /^standup for @?(\w+)$/i, builder: (match) => ({ time: { last: "24h" }, people: { owner: [match[1]] }, output: { format: "summary", sort: "time", groupBy: "frame" } }) }, { name: "error-investigation", description: "Investigate errors in a specific component", pattern: /^investigate errors? in (.+)$/i, builder: (match) => ({ content: { topic: ["error", "bug"], keywords: [match[1]] }, frame: { type: [FrameType.BUG, FrameType.DEBUG] }, time: { last: "48h" }, output: { format: "full", sort: "time", include: ["events", "digests"] } }) }, { name: "feature-progress", description: "Check progress on a specific feature", pattern: /^progress on (.+) feature$/i, builder: (match) => ({ content: { topic: ["feature"], keywords: [match[1]] }, frame: { type: [FrameType.FEATURE], status: [FrameStatus.OPEN] }, output: { format: "summary", sort: "score" } }) }, { name: "code-review", description: "Find recent changes for code review", pattern: /^code review for (.+)$/i, builder: (match) => { const target = match[1]; const isFile = target.includes("."); return { content: isFile ? { files: [target] } : { topic: [target] }, time: { last: "24h" }, output: { format: "full", include: ["events", "digests"], sort: "time" } }; } }, { name: "team-retrospective", description: "Gather team work for retrospective", pattern: /^retrospective for (last|this) (week|sprint|month)$/i, builder: (match) => { const timeMap = { week: "7d", sprint: "14d", month: "30d" }; return { people: { team: "$current_team" }, time: { last: timeMap[match[2]] || "7d" }, output: { format: "summary", groupBy: "owner", sort: "score" } }; } }, { name: "performance-analysis", description: "Analyze performance issues", pattern: /^performance (issues?|problems?|analysis) for (.+)$/i, builder: (match) => ({ content: { topic: ["performance", "optimization", "slow", "latency"], keywords: [match[2]] }, time: { last: "7d" }, output: { format: "full", sort: "score" } }) }, { name: "security-audit", description: "Security-related frames", pattern: /^security audit( for (.+))?$/i, builder: (match) => ({ content: { topic: ["security", "vulnerability", "auth", "authorization"], keywords: match[2] ? [match[2]] : void 0 }, frame: { score: { min: 0.7 } // High priority for security }, output: { format: "full", sort: "score" } }) }, { name: "deployment-readiness", description: "Check deployment readiness", pattern: /^deployment readiness( for (.+))?$/i, builder: (match) => ({ content: { topic: ["deployment", "release", "production"], keywords: match[2] ? [match[2]] : void 0 }, frame: { status: [FrameStatus.OPEN] }, time: { last: "48h" }, output: { format: "summary", sort: "score" } }) } ]; /** * Match query against templates */ matchTemplate(query) { for (const template of this.templates) { const match = query.match(template.pattern); if (match) { return template.builder(match); } } return null; } /** * Get all template names and descriptions */ getTemplateInfo() { return this.templates.map((t) => ({ name: t.name, description: t.description })); } /** * Add custom template */ addTemplate(template) { this.templates.push(template); } } class InlineModifierParser { modifierPatterns = { time: /\+last:(\d+[hdwm])/gi, since: /\+since:(\S+)/gi, until: /\+until:(\S+)/gi, owner: /\+owner:@?(\w+)/gi, team: /\+team:(\w+)/gi, topic: /\+topic:(\w+)/gi, file: /\+file:(\S+)/gi, sort: /\+sort:(time|score|relevance)/gi, limit: /\+limit:(\d+)/gi, format: /\+format:(full|summary|ids)/gi, group: /\+group:(frame|time|owner|topic)/gi, status: /\+status:(open|closed|stalled)/gi, priority: /\+priority:(critical|high|medium|low)/gi }; /** * Parse inline modifiers from query */ parse(query) { const modifiers = {}; let cleanQuery = query; const lastMatch = [...query.matchAll(this.modifierPatterns.time)]; if (lastMatch.length > 0) { modifiers.time = { last: lastMatch[0][1] }; cleanQuery = cleanQuery.replace(this.modifierPatterns.time, ""); } const sinceMatch = [...query.matchAll(this.modifierPatterns.since)]; if (sinceMatch.length > 0) { const date = new Date(sinceMatch[0][1]); if (!isNaN(date.getTime())) { modifiers.time = { ...modifiers.time, since: date }; } cleanQuery = cleanQuery.replace(this.modifierPatterns.since, ""); } const untilMatch = [...query.matchAll(this.modifierPatterns.until)]; if (untilMatch.length > 0) { const date = new Date(untilMatch[0][1]); if (!isNaN(date.getTime())) { modifiers.time = { ...modifiers.time, until: date }; } cleanQuery = cleanQuery.replace(this.modifierPatterns.until, ""); } const ownerMatches = [...query.matchAll(this.modifierPatterns.owner)]; if (ownerMatches.length > 0) { modifiers.people = { owner: ownerMatches.map((m) => m[1]) }; cleanQuery = cleanQuery.replace(this.modifierPatterns.owner, ""); } const teamMatch = [...query.matchAll(this.modifierPatterns.team)]; if (teamMatch.length > 0) { modifiers.people = { ...modifiers.people, team: teamMatch[0][1] }; cleanQuery = cleanQuery.replace(this.modifierPatterns.team, ""); } const topicMatches = [...query.matchAll(this.modifierPatterns.topic)]; if (topicMatches.length > 0) { modifiers.content = { topic: topicMatches.map((m) => m[1]) }; cleanQuery = cleanQuery.replace(this.modifierPatterns.topic, ""); } const fileMatches = [...query.matchAll(this.modifierPatterns.file)]; if (fileMatches.length > 0) { modifiers.content = { ...modifiers.content, files: fileMatches.map((m) => m[1]) }; cleanQuery = cleanQuery.replace(this.modifierPatterns.file, ""); } const sortMatch = [...query.matchAll(this.modifierPatterns.sort)]; if (sortMatch.length > 0) { modifiers.output = { sort: sortMatch[0][1] }; cleanQuery = cleanQuery.replace(this.modifierPatterns.sort, ""); } const limitMatch = [...query.matchAll(this.modifierPatterns.limit)]; if (limitMatch.length > 0) { modifiers.output = { ...modifiers.output, limit: parseInt(limitMatch[0][1]) }; cleanQuery = cleanQuery.replace(this.modifierPatterns.limit, ""); } const formatMatch = [...query.matchAll(this.modifierPatterns.format)]; if (formatMatch.length > 0) { modifiers.output = { ...modifiers.output, format: formatMatch[0][1] }; cleanQuery = cleanQuery.replace(this.modifierPatterns.format, ""); } const groupMatch = [...query.matchAll(this.modifierPatterns.group)]; if (groupMatch.length > 0) { modifiers.output = { ...modifiers.output, groupBy: groupMatch[0][1] }; cleanQuery = cleanQuery.replace(this.modifierPatterns.group, ""); } const statusMatch = [...query.matchAll(this.modifierPatterns.status)]; if (statusMatch.length > 0) { const statusMap = { open: FrameStatus.OPEN, closed: FrameStatus.CLOSED, stalled: FrameStatus.STALLED }; modifiers.frame = { status: statusMatch.map((m) => statusMap[m[1]]) }; cleanQuery = cleanQuery.replace(this.modifierPatterns.status, ""); } const priorityMatch = [...query.matchAll(this.modifierPatterns.priority)]; if (priorityMatch.length > 0) { const priorityMap = { critical: { min: 0.8 }, high: { min: 0.7, max: 0.8 }, medium: { min: 0.4, max: 0.7 }, low: { max: 0.4 } }; modifiers.frame = { ...modifiers.frame, score: priorityMap[priorityMatch[0][1]] }; cleanQuery = cleanQuery.replace(this.modifierPatterns.priority, ""); } cleanQuery = cleanQuery.replace(/\s+/g, " ").trim(); return { cleanQuery, modifiers }; } } export { InlineModifierParser, QueryTemplates }; //# sourceMappingURL=query-templates.js.map