@triedotdev/mcp 1.0.88 → 1.0.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +11 -3
- package/dist/{agent-smith-MCKGNWPL.js → agent-smith-KIFP2XG3.js} +4 -4
- package/dist/{agent-smith-runner-GP5HLL7E.js → agent-smith-runner-Z73W5DR5.js} +4 -4
- package/dist/{chunk-YSES743V.js → chunk-3HTPH3P2.js} +14 -13
- package/dist/chunk-3HTPH3P2.js.map +1 -0
- package/dist/{chunk-HNDHVFA3.js → chunk-A44W6SZJ.js} +17 -16
- package/dist/chunk-A44W6SZJ.js.map +1 -0
- package/dist/{chunk-Z6JP2QQU.js → chunk-BBEFK56U.js} +27 -26
- package/dist/chunk-BBEFK56U.js.map +1 -0
- package/dist/{chunk-X3E6ISEG.js → chunk-CFE7FZU7.js} +7 -4
- package/dist/chunk-CFE7FZU7.js.map +1 -0
- package/dist/{chunk-KGVKUMFO.js → chunk-D35TI7NY.js} +2 -2
- package/dist/{chunk-CM7EHNQK.js → chunk-D5VEUZLP.js} +33 -2
- package/dist/chunk-D5VEUZLP.js.map +1 -0
- package/dist/{chunk-TBRU735C.js → chunk-F3WW4FY2.js} +6 -3
- package/dist/chunk-F3WW4FY2.js.map +1 -0
- package/dist/{chunk-DXBYHIA7.js → chunk-G4DUCCMT.js} +8 -8
- package/dist/{chunk-DCJKNE2L.js → chunk-GMKPXL4Q.js} +4 -3
- package/dist/chunk-GMKPXL4Q.js.map +1 -0
- package/dist/{chunk-7UPNCM66.js → chunk-JG2TAVAO.js} +14 -13
- package/dist/chunk-JG2TAVAO.js.map +1 -0
- package/dist/{chunk-THJKXIMJ.js → chunk-OXZKSR6J.js} +7 -4
- package/dist/chunk-OXZKSR6J.js.map +1 -0
- package/dist/{chunk-TDWPEV3N.js → chunk-PFWGEHIA.js} +8 -5
- package/dist/chunk-PFWGEHIA.js.map +1 -0
- package/dist/{chunk-PH4HZEAM.js → chunk-QH5XB4K6.js} +6 -5
- package/dist/chunk-QH5XB4K6.js.map +1 -0
- package/dist/{chunk-4CYQGEWE.js → chunk-TBL3FWWG.js} +22 -21
- package/dist/chunk-TBL3FWWG.js.map +1 -0
- package/dist/cli/create-agent.js +2 -2
- package/dist/cli/main.js +16 -15
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +12 -12
- package/dist/{goal-manager-JTM6MOZG.js → goal-manager-7D3GUJVV.js} +5 -5
- package/dist/guardian-agent-QBYV2JLR.js +21 -0
- package/dist/index.js +23 -22
- package/dist/index.js.map +1 -1
- package/dist/{issue-store-AZ3D4LOG.js → issue-store-WTXCQZEA.js} +3 -3
- package/dist/workers/agent-worker.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-4CYQGEWE.js.map +0 -1
- package/dist/chunk-7UPNCM66.js.map +0 -1
- package/dist/chunk-CM7EHNQK.js.map +0 -1
- package/dist/chunk-DCJKNE2L.js.map +0 -1
- package/dist/chunk-HNDHVFA3.js.map +0 -1
- package/dist/chunk-PH4HZEAM.js.map +0 -1
- package/dist/chunk-TBRU735C.js.map +0 -1
- package/dist/chunk-TDWPEV3N.js.map +0 -1
- package/dist/chunk-THJKXIMJ.js.map +0 -1
- package/dist/chunk-X3E6ISEG.js.map +0 -1
- package/dist/chunk-YSES743V.js.map +0 -1
- package/dist/chunk-Z6JP2QQU.js.map +0 -1
- package/dist/guardian-agent-RIF7XBFL.js +0 -21
- /package/dist/{agent-smith-MCKGNWPL.js.map → agent-smith-KIFP2XG3.js.map} +0 -0
- /package/dist/{agent-smith-runner-GP5HLL7E.js.map → agent-smith-runner-Z73W5DR5.js.map} +0 -0
- /package/dist/{chunk-KGVKUMFO.js.map → chunk-D35TI7NY.js.map} +0 -0
- /package/dist/{chunk-DXBYHIA7.js.map → chunk-G4DUCCMT.js.map} +0 -0
- /package/dist/{goal-manager-JTM6MOZG.js.map → goal-manager-7D3GUJVV.js.map} +0 -0
- /package/dist/{guardian-agent-RIF7XBFL.js.map → guardian-agent-QBYV2JLR.js.map} +0 -0
- /package/dist/{issue-store-AZ3D4LOG.js.map → issue-store-WTXCQZEA.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/memory/issue-store.ts","../src/memory/bm25.ts","../src/memory/compactor.ts","../src/utils/atomic-write.ts","../src/utils/backup-manager.ts","../src/memory/validation.ts","../src/memory/ledger.ts"],"sourcesContent":["/**\n * Issue Memory Store\n * \n * Stores issues for semantic search and pattern detection.\n * Uses BM25 ranking for search (same algorithm as Elasticsearch).\n * Local JSON storage with daily logs.\n * \n * Phase 1 Hardening:\n * - SHA256 hashing for proper deduplication\n * - Atomic writes to prevent corruption\n * - Rotational backups for recovery\n * - Zod validation for data integrity\n */\n\nimport { mkdir, writeFile, readFile, readdir } from 'fs/promises';\nimport { createHash } from 'crypto';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getWorkingDirectory, getTrieDirectory } from '../utils/workspace.js';\nimport type { Issue } from '../types/index.js';\nimport { BM25Index } from './bm25.js';\nimport { compactOldIssues, saveCompactedSummary, getHistoricalInsights } from './compactor.js';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { BackupManager } from '../utils/backup-manager.js';\nimport { IssueIndexSchema, safeParseAndValidate } from './validation.js';\nimport { appendIssuesToLedger } from './ledger.js';\n\nexport interface StoredIssue {\n id: string;\n hash: string;\n severity: string;\n issue: string;\n fix: string;\n file: string;\n line: number | undefined;\n agent: string;\n category: string | undefined;\n timestamp: string;\n project: string;\n resolved: boolean | undefined;\n resolvedAt: string | undefined;\n}\n\nexport interface IssueSearchResult {\n issue: StoredIssue;\n score: number;\n matchType: 'bm25' | 'keyword' | 'fts5';\n}\n\nexport interface IssueMemoryStats {\n totalIssues: number;\n issuesByAgent: Record<string, number>;\n issuesBySeverity: Record<string, number>;\n oldestIssue: string | undefined;\n newestIssue: string | undefined;\n resolvedCount: number;\n historicalIssues: number;\n improvementTrend: 'improving' | 'stable' | 'declining' | 'unknown';\n capacityInfo: {\n current: number;\n max: number;\n percentFull: number;\n isAtCap: boolean;\n };\n deduplicationStats: {\n duplicatesAvoided: number;\n uniquePatterns: number;\n };\n}\n\n/**\n * Store issues from a scan\n * Returns number of unique issues added (after deduplication)\n */\nexport async function storeIssues(\n issues: Issue[],\n project: string,\n workDir?: string\n): Promise<{ stored: number; duplicates: number }> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n \n const stored: StoredIssue[] = [];\n const now = new Date().toISOString();\n const seenHashes = new Set<string>();\n let duplicates = 0;\n \n for (const issue of issues) {\n const hash = hashIssue(issue);\n \n // Skip duplicates within the same scan\n if (seenHashes.has(hash)) {\n duplicates++;\n continue;\n }\n seenHashes.add(hash);\n \n const storedIssue: StoredIssue = {\n id: issue.id,\n hash,\n severity: issue.severity,\n issue: issue.issue,\n fix: issue.fix,\n file: issue.file,\n line: issue.line,\n agent: issue.agent,\n category: issue.category,\n timestamp: now,\n project,\n resolved: false,\n resolvedAt: undefined,\n };\n stored.push(storedIssue);\n }\n\n await appendToDailyLog(stored, projectDir);\n await appendIssuesToLedger(stored, projectDir);\n const dedupedCount = await updateIssueIndex(stored, projectDir);\n \n return { stored: dedupedCount, duplicates: duplicates + (stored.length - dedupedCount) };\n}\n\n/**\n * Search issues using BM25 ranking (same algorithm as Elasticsearch)\n */\nexport async function searchIssues(\n query: string,\n options: {\n workDir?: string;\n limit?: number;\n project?: string;\n severity?: string[];\n agent?: string;\n includeResolved?: boolean;\n } = {}\n): Promise<IssueSearchResult[]> {\n const projectDir = options.workDir || getWorkingDirectory(undefined, true);\n const limit = options.limit || 10;\n const allIssues = await loadIssueIndex(projectDir);\n \n if (allIssues.length === 0) {\n return [];\n }\n\n // Filter issues first\n const filteredIssues = allIssues.filter(issue => {\n if (options.project && issue.project !== options.project) return false;\n if (options.severity && !options.severity.includes(issue.severity)) return false;\n if (options.agent && issue.agent !== options.agent) return false;\n if (!options.includeResolved && issue.resolved) return false;\n return true;\n });\n\n if (filteredIssues.length === 0) {\n return [];\n }\n\n // Build BM25 index\n const bm25 = new BM25Index();\n const issueMap = new Map<string, StoredIssue>();\n \n for (const issue of filteredIssues) {\n const searchText = `${issue.issue} ${issue.fix} ${issue.file} ${issue.agent} ${issue.category || ''} ${issue.severity}`;\n bm25.addDocument({\n id: issue.id,\n text: searchText,\n });\n issueMap.set(issue.id, issue);\n }\n\n // Search with BM25\n const bm25Results = bm25.search(query, limit);\n \n return bm25Results.map(result => ({\n issue: issueMap.get(result.id)!,\n score: result.score,\n matchType: 'bm25' as const,\n }));\n}\n\n/**\n * Find similar issues using BM25 similarity\n */\nexport async function findSimilarIssues(\n issue: Issue,\n options: {\n workDir?: string;\n limit?: number;\n excludeSameFile?: boolean;\n } = {}\n): Promise<IssueSearchResult[]> {\n // Use the issue description and fix as the query for similarity\n const query = `${issue.issue} ${issue.fix} ${issue.agent}`;\n const searchOptions: Parameters<typeof searchIssues>[1] = {\n limit: (options.limit || 5) + 5, // Get extra to account for filtering\n includeResolved: true,\n };\n if (options.workDir !== undefined) {\n searchOptions.workDir = options.workDir;\n }\n const results = await searchIssues(query, searchOptions);\n\n let filtered = results.filter(r => r.issue.id !== issue.id);\n \n if (options.excludeSameFile) {\n filtered = filtered.filter(r => r.issue.file !== issue.file);\n }\n \n return filtered.slice(0, options.limit || 5);\n}\n\n/**\n * Mark an issue as resolved\n */\nexport async function markIssueResolved(\n issueId: string,\n workDir?: string\n): Promise<boolean> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n \n const issue = index.find(i => i.id === issueId);\n if (!issue) return false;\n \n issue.resolved = true;\n issue.resolvedAt = new Date().toISOString();\n \n await saveIssueIndex(index, projectDir);\n return true;\n}\n\n/**\n * Get memory statistics including historical insights\n */\nexport async function getMemoryStats(workDir?: string): Promise<IssueMemoryStats> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n const historical = await getHistoricalInsights(projectDir);\n \n const MAX_ISSUES = 10000;\n const uniqueHashes = new Set(index.map(i => i.hash));\n \n const stats: IssueMemoryStats = {\n totalIssues: index.length,\n issuesByAgent: {},\n issuesBySeverity: {},\n oldestIssue: undefined,\n newestIssue: undefined,\n resolvedCount: 0,\n historicalIssues: historical.totalHistoricalIssues,\n improvementTrend: historical.improvementTrend,\n capacityInfo: {\n current: index.length,\n max: MAX_ISSUES,\n percentFull: Math.round((index.length / MAX_ISSUES) * 100),\n isAtCap: index.length >= MAX_ISSUES,\n },\n deduplicationStats: {\n duplicatesAvoided: index.length - uniqueHashes.size,\n uniquePatterns: uniqueHashes.size,\n },\n };\n\n for (const issue of index) {\n stats.issuesByAgent[issue.agent] = (stats.issuesByAgent[issue.agent] || 0) + 1;\n stats.issuesBySeverity[issue.severity] = (stats.issuesBySeverity[issue.severity] || 0) + 1;\n if (issue.resolved) stats.resolvedCount++;\n }\n\n if (index.length > 0) {\n const sorted = [...index].sort((a, b) => \n new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n const oldest = sorted[0]?.timestamp;\n const newest = sorted[sorted.length - 1]?.timestamp;\n if (oldest !== undefined) {\n stats.oldestIssue = oldest;\n }\n if (newest !== undefined) {\n stats.newestIssue = newest;\n }\n }\n\n return stats;\n}\n\n/**\n * Get recent issues\n */\nexport async function getRecentIssues(\n options: {\n workDir?: string;\n limit?: number;\n daysBack?: number;\n } = {}\n): Promise<StoredIssue[]> {\n const projectDir = options.workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n const limit = options.limit || 20;\n const daysBack = options.daysBack || 7;\n \n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - daysBack);\n \n return index\n .filter(i => new Date(i.timestamp) >= cutoff)\n .sort((a, b) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime())\n .slice(0, limit);\n}\n\n/**\n * Purge issues from memory\n * Offers different strategies for managing memory capacity\n */\nexport async function purgeIssues(\n strategy: 'smart' | 'resolved' | 'old' | 'all',\n options: {\n workDir?: string;\n daysOld?: number;\n } = {}\n): Promise<{ removed: number; remaining: number; strategy: string }> {\n const projectDir = options.workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n const originalCount = index.length;\n \n let remaining: StoredIssue[] = [];\n \n switch (strategy) {\n case 'smart':\n // Keep: critical/high severity, recent (< 30 days), unresolved\n const thirtyDaysAgo = new Date();\n thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);\n \n remaining = index.filter(i => {\n const isRecent = new Date(i.timestamp) >= thirtyDaysAgo;\n const isImportant = ['critical', 'high'].includes(i.severity);\n const isUnresolved = !i.resolved;\n \n return isRecent || isImportant || isUnresolved;\n });\n break;\n \n case 'resolved':\n // Remove all resolved issues\n remaining = index.filter(i => !i.resolved);\n break;\n \n case 'old':\n // Remove issues older than specified days (default 90)\n const daysOld = options.daysOld || 90;\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - daysOld);\n \n remaining = index.filter(i => new Date(i.timestamp) >= cutoffDate);\n break;\n \n case 'all':\n // Clear all issues (keeps compacted summaries)\n remaining = [];\n break;\n }\n \n await saveIssueIndex(remaining, projectDir);\n \n return {\n removed: originalCount - remaining.length,\n remaining: remaining.length,\n strategy,\n };\n}\n\n/**\n * Get daily log files\n */\nexport async function getDailyLogs(workDir?: string): Promise<string[]> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n \n try {\n if (!existsSync(memoryDir)) return [];\n const files = await readdir(memoryDir);\n return files\n .filter(f => /^\\d{4}-\\d{2}-\\d{2}\\.md$/.test(f))\n .sort()\n .reverse();\n } catch {\n return [];\n }\n}\n\n// Private helpers\n\nasync function appendToDailyLog(issues: StoredIssue[], projectDir: string): Promise<void> {\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const today = new Date().toISOString().split('T')[0];\n const logPath = join(memoryDir, `${today}.md`);\n\n let content = '';\n \n try {\n if (existsSync(logPath)) {\n content = await readFile(logPath, 'utf-8');\n } else {\n content = `# Issue Log: ${today}\\n\\n`;\n }\n } catch {\n content = `# Issue Log: ${today}\\n\\n`;\n }\n\n const time = new Date().toTimeString().split(' ')[0];\n \n const newEntries = issues.map(i => \n `## [${time}] ${i.severity.toUpperCase()}: ${i.issue.slice(0, 80)}${i.issue.length > 80 ? '...' : ''}\\n` +\n `- **File:** \\`${i.file}\\`${i.line ? `:${i.line}` : ''}\\n` +\n `- **Agent:** ${i.agent}\\n` +\n `- **Fix:** ${i.fix.slice(0, 200)}${i.fix.length > 200 ? '...' : ''}\\n`\n ).join('\\n');\n\n content += newEntries + '\\n';\n \n await writeFile(logPath, content);\n}\n\n/**\n * Load issue index with validation and auto-recovery\n * \n * If the file is corrupted:\n * 1. Attempts to recover from the most recent valid backup\n * 2. Returns empty array if no valid backup exists\n */\nasync function loadIssueIndex(projectDir: string): Promise<StoredIssue[]> {\n const indexPath = join(getTrieDirectory(projectDir), 'memory', 'issues.json');\n \n try {\n if (existsSync(indexPath)) {\n const content = await readFile(indexPath, 'utf-8');\n const result = safeParseAndValidate(content, IssueIndexSchema);\n \n if (result.success) {\n return result.data as StoredIssue[];\n }\n \n // Validation failed - attempt recovery from backup\n console.error(` Issue index corrupted: ${result.error}`);\n const backupManager = new BackupManager(indexPath);\n \n if (await backupManager.recoverFromBackup()) {\n console.error(' ✅ Recovered from backup');\n const recovered = await readFile(indexPath, 'utf-8');\n const recoveredResult = safeParseAndValidate(recovered, IssueIndexSchema);\n if (recoveredResult.success) {\n return recoveredResult.data as StoredIssue[];\n }\n }\n \n console.error(' No valid backup found, starting fresh');\n }\n } catch {\n // Index doesn't exist or recovery failed\n }\n \n return [];\n}\n\nasync function updateIssueIndex(newIssues: StoredIssue[], projectDir: string): Promise<number> {\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n \n let existing = await loadIssueIndex(projectDir);\n \n // Intelligent deduplication: only add truly unique issues\n // Issues are unique if they have different hash (content + file + severity + agent)\n const hashSet = new Set(existing.map(i => i.hash));\n const toAdd = newIssues.filter(i => !hashSet.has(i.hash));\n const dedupedCount = toAdd.length;\n \n existing = [...existing, ...toAdd];\n \n // Intelligent compaction: summarize old issues instead of deleting\n if (existing.length > 500) {\n const { summary, remaining } = await compactOldIssues(existing, {\n keepDays: 30,\n minIssuesToCompact: 100,\n });\n \n if (summary) {\n await saveCompactedSummary(summary, projectDir);\n existing = remaining;\n }\n }\n \n // Hard cap: prune to 10,000 if still too large\n // Prioritize: 1) Recent issues, 2) High severity, 3) Unresolved\n if (existing.length > 10000) {\n existing = intelligentPrune(existing, 10000);\n }\n \n await saveIssueIndex(existing, projectDir);\n return dedupedCount;\n}\n\n/**\n * Intelligently prune issues to target count\n * Prioritizes: recent, high severity, unresolved\n */\nfunction intelligentPrune(issues: StoredIssue[], targetCount: number): StoredIssue[] {\n const severityWeight: Record<string, number> = {\n critical: 100,\n high: 50,\n moderate: 20,\n low: 10,\n info: 5,\n };\n \n const scored = issues.map(issue => {\n const ageInDays = (Date.now() - new Date(issue.timestamp).getTime()) / (1000 * 60 * 60 * 24);\n const recencyScore = Math.max(0, 100 - ageInDays * 2); // Newer = higher score\n const severityScore = severityWeight[issue.severity] || 10;\n const resolvedPenalty = issue.resolved ? -50 : 0;\n \n return {\n issue,\n score: recencyScore + severityScore + resolvedPenalty,\n };\n });\n \n return scored\n .sort((a, b) => b.score - a.score)\n .slice(0, targetCount)\n .map(s => s.issue);\n}\n\n/**\n * Save issue index with backup and atomic write\n * \n * 1. Creates a backup of the existing file\n * 2. Writes the new data atomically (temp file + rename)\n * 3. Maintains up to 5 rotational backups\n */\nasync function saveIssueIndex(issues: StoredIssue[], projectDir: string): Promise<void> {\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n \n const indexPath = join(memoryDir, 'issues.json');\n \n // Create backup before writing\n const backupManager = new BackupManager(indexPath);\n await backupManager.createBackup();\n \n // Atomic write\n await atomicWriteJSON(indexPath, issues);\n}\n\n/**\n * Hash an issue using SHA256 for proper deduplication\n * \n * Uses cryptographic hashing to eliminate collision risk.\n * The hash is truncated to 16 characters for storage efficiency\n * while still providing effectively zero collision probability.\n */\nfunction hashIssue(issue: Issue): string {\n const content = `${issue.issue}|${issue.file}|${issue.severity}|${issue.agent}`;\n return createHash('sha256').update(content).digest('hex').slice(0, 16);\n}\n\n","/**\n * BM25 Search Implementation\n * \n * BM25 (Best Match 25) is a ranking function used by search engines.\n * It's more sophisticated than TF-IDF and handles term frequency saturation.\n * \n * This is the same algorithm used by Elasticsearch.\n */\n\nexport interface BM25Document {\n id: string;\n text: string;\n metadata?: Record<string, unknown>;\n}\n\nexport interface BM25Result {\n id: string;\n score: number;\n metadata?: Record<string, unknown>;\n}\n\nexport class BM25Index {\n private documents: Map<string, BM25Document> = new Map();\n private termFrequencies: Map<string, Map<string, number>> = new Map();\n private documentFrequencies: Map<string, number> = new Map();\n private documentLengths: Map<string, number> = new Map();\n private avgDocLength: number = 0;\n private k1: number = 1.5;\n private b: number = 0.75;\n\n /**\n * Add a document to the index\n */\n addDocument(doc: BM25Document): void {\n const tokens = this.tokenize(doc.text);\n this.documents.set(doc.id, doc);\n this.documentLengths.set(doc.id, tokens.length);\n\n const termFreq = new Map<string, number>();\n const seenTerms = new Set<string>();\n\n for (const token of tokens) {\n termFreq.set(token, (termFreq.get(token) || 0) + 1);\n \n if (!seenTerms.has(token)) {\n seenTerms.add(token);\n this.documentFrequencies.set(token, (this.documentFrequencies.get(token) || 0) + 1);\n }\n }\n\n this.termFrequencies.set(doc.id, termFreq);\n this.updateAvgDocLength();\n }\n\n /**\n * Add multiple documents\n */\n addDocuments(docs: BM25Document[]): void {\n for (const doc of docs) {\n this.addDocument(doc);\n }\n }\n\n /**\n * Search the index\n */\n search(query: string, limit: number = 10): BM25Result[] {\n const queryTokens = this.tokenize(query);\n const scores: Map<string, number> = new Map();\n const N = this.documents.size;\n\n for (const [docId] of this.documents) {\n let score = 0;\n const docLength = this.documentLengths.get(docId) || 0;\n const termFreqs = this.termFrequencies.get(docId);\n\n if (!termFreqs) continue;\n\n for (const term of queryTokens) {\n const tf = termFreqs.get(term) || 0;\n if (tf === 0) continue;\n\n const df = this.documentFrequencies.get(term) || 0;\n const idf = Math.log((N - df + 0.5) / (df + 0.5) + 1);\n\n const numerator = tf * (this.k1 + 1);\n const denominator = tf + this.k1 * (1 - this.b + this.b * (docLength / this.avgDocLength));\n \n score += idf * (numerator / denominator);\n }\n\n if (score > 0) {\n scores.set(docId, score);\n }\n }\n\n return Array.from(scores.entries())\n .sort((a, b) => b[1] - a[1])\n .slice(0, limit)\n .map(([id, score]) => {\n const metadata = this.documents.get(id)?.metadata;\n const result: BM25Result = { id, score };\n if (metadata !== undefined) {\n result.metadata = metadata;\n }\n return result;\n });\n }\n\n /**\n * Get document count\n */\n get size(): number {\n return this.documents.size;\n }\n\n /**\n * Clear the index\n */\n clear(): void {\n this.documents.clear();\n this.termFrequencies.clear();\n this.documentFrequencies.clear();\n this.documentLengths.clear();\n this.avgDocLength = 0;\n }\n\n /**\n * Serialize the index to JSON\n */\n serialize(): string {\n return JSON.stringify({\n documents: Array.from(this.documents.entries()),\n termFrequencies: Array.from(this.termFrequencies.entries()).map(([k, v]) => [k, Array.from(v.entries())]),\n documentFrequencies: Array.from(this.documentFrequencies.entries()),\n documentLengths: Array.from(this.documentLengths.entries()),\n avgDocLength: this.avgDocLength,\n });\n }\n\n /**\n * Load from serialized JSON\n */\n static deserialize(json: string): BM25Index {\n const data = JSON.parse(json);\n const index = new BM25Index();\n \n index.documents = new Map(data.documents);\n index.termFrequencies = new Map(data.termFrequencies.map(([k, v]: [string, [string, number][]]) => [k, new Map(v)]));\n index.documentFrequencies = new Map(data.documentFrequencies);\n index.documentLengths = new Map(data.documentLengths);\n index.avgDocLength = data.avgDocLength;\n \n return index;\n }\n\n private tokenize(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/[^\\w\\s]/g, ' ')\n .split(/\\s+/)\n .filter(token => token.length > 2 && !this.isStopWord(token));\n }\n\n private isStopWord(word: string): boolean {\n const stopWords = new Set([\n 'the', 'be', 'to', 'of', 'and', 'a', 'in', 'that', 'have', 'i',\n 'it', 'for', 'not', 'on', 'with', 'he', 'as', 'you', 'do', 'at',\n 'this', 'but', 'his', 'by', 'from', 'they', 'we', 'say', 'her', 'she',\n 'or', 'an', 'will', 'my', 'one', 'all', 'would', 'there', 'their', 'what',\n 'so', 'up', 'out', 'if', 'about', 'who', 'get', 'which', 'go', 'me',\n 'when', 'make', 'can', 'like', 'time', 'no', 'just', 'him', 'know', 'take',\n 'into', 'year', 'your', 'some', 'could', 'them', 'see', 'other', 'than', 'then',\n 'now', 'look', 'only', 'come', 'its', 'over', 'also', 'back', 'after', 'use',\n 'two', 'how', 'our', 'first', 'way', 'even', 'new', 'want', 'because', 'any',\n 'these', 'give', 'day', 'most', 'us', 'should', 'been', 'has', 'was', 'are',\n ]);\n return stopWords.has(word);\n }\n\n private updateAvgDocLength(): void {\n if (this.documentLengths.size === 0) {\n this.avgDocLength = 0;\n return;\n }\n const total = Array.from(this.documentLengths.values()).reduce((a, b) => a + b, 0);\n this.avgDocLength = total / this.documentLengths.size;\n }\n}\n","/**\n * Memory Compactor\n * \n * Intelligently compacts old issues into summaries instead of deleting them.\n * Preserves patterns and insights while reducing storage.\n * \n * Phase 1 Hardening:\n * - Atomic writes to prevent corruption\n * - Backup rotation for recovery\n * - Zod validation for data integrity\n */\n\nimport { mkdir, readFile } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getTrieDirectory } from '../utils/workspace.js';\nimport type { StoredIssue } from './issue-store.js';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { BackupManager } from '../utils/backup-manager.js';\nimport { CompactedSummariesIndexSchema, safeParseAndValidate } from './validation.js';\n\nexport interface CompactedSummary {\n period: string;\n startDate: string;\n endDate: string;\n totalIssues: number;\n resolvedCount: number;\n bySeverity: Record<string, number>;\n byAgent: Record<string, number>;\n topPatterns: PatternSummary[];\n hotFiles: { file: string; count: number }[];\n compactedAt: string;\n}\n\nexport interface PatternSummary {\n pattern: string;\n count: number;\n severity: string;\n agent: string;\n exampleFix: string;\n}\n\n/**\n * Compact old issues into summaries\n * Returns the compacted summary and the remaining (recent) issues\n */\nexport async function compactOldIssues(\n issues: StoredIssue[],\n options: {\n keepDays?: number;\n minIssuesToCompact?: number;\n } = {}\n): Promise<{ summary: CompactedSummary | null; remaining: StoredIssue[] }> {\n const keepDays = options.keepDays ?? 30;\n const minIssues = options.minIssuesToCompact ?? 100;\n \n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - keepDays);\n \n const oldIssues = issues.filter(i => new Date(i.timestamp) < cutoffDate);\n const recentIssues = issues.filter(i => new Date(i.timestamp) >= cutoffDate);\n \n // Only compact if we have enough old issues\n if (oldIssues.length < minIssues) {\n return { summary: null, remaining: issues };\n }\n \n // Build summary\n const summary = buildSummary(oldIssues);\n \n return { summary, remaining: recentIssues };\n}\n\n/**\n * Build a summary from a set of issues\n */\nfunction buildSummary(issues: StoredIssue[]): CompactedSummary {\n const sorted = issues.sort((a, b) => \n new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\n );\n \n const bySeverity: Record<string, number> = {};\n const byAgent: Record<string, number> = {};\n const patternMap: Map<string, { count: number; issue: StoredIssue }> = new Map();\n const fileCount: Map<string, number> = new Map();\n \n for (const issue of issues) {\n // Count by severity\n bySeverity[issue.severity] = (bySeverity[issue.severity] || 0) + 1;\n \n // Count by agent\n byAgent[issue.agent] = (byAgent[issue.agent] || 0) + 1;\n \n // Track patterns (normalized issue text)\n const patternKey = normalizePattern(issue.issue);\n const existing = patternMap.get(patternKey);\n if (existing) {\n existing.count++;\n } else {\n patternMap.set(patternKey, { count: 1, issue });\n }\n \n // Count files\n const fileName = issue.file.split('/').pop() || issue.file;\n fileCount.set(fileName, (fileCount.get(fileName) || 0) + 1);\n }\n \n // Get top patterns\n const topPatterns = Array.from(patternMap.entries())\n .sort((a, b) => b[1].count - a[1].count)\n .slice(0, 10)\n .map(([pattern, data]) => ({\n pattern: pattern.slice(0, 100),\n count: data.count,\n severity: data.issue.severity,\n agent: data.issue.agent,\n exampleFix: data.issue.fix.slice(0, 200),\n }));\n \n // Get hot files\n const hotFiles = Array.from(fileCount.entries())\n .sort((a, b) => b[1] - a[1])\n .slice(0, 10)\n .map(([file, count]) => ({ file, count }));\n \n return {\n period: `${sorted[0]?.timestamp.split('T')[0]} to ${sorted[sorted.length - 1]?.timestamp.split('T')[0]}`,\n startDate: sorted[0]?.timestamp || '',\n endDate: sorted[sorted.length - 1]?.timestamp || '',\n totalIssues: issues.length,\n resolvedCount: issues.filter(i => i.resolved).length,\n bySeverity,\n byAgent,\n topPatterns,\n hotFiles,\n compactedAt: new Date().toISOString(),\n };\n}\n\n/**\n * Normalize issue text for pattern matching\n */\nfunction normalizePattern(text: string): string {\n return text\n .toLowerCase()\n .replace(/`[^`]+`/g, 'CODE')\n .replace(/\\b\\d+\\b/g, 'N')\n .replace(/[\"']/g, '')\n .replace(/\\s+/g, ' ')\n .trim()\n .slice(0, 150);\n}\n\n/**\n * Save compacted summary to disk with atomic write and backup\n */\nexport async function saveCompactedSummary(\n summary: CompactedSummary,\n projectDir: string\n): Promise<void> {\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n \n const summaryPath = join(memoryDir, 'compacted-summaries.json');\n \n let summaries: CompactedSummary[] = [];\n try {\n if (existsSync(summaryPath)) {\n const content = await readFile(summaryPath, 'utf-8');\n const result = safeParseAndValidate(content, CompactedSummariesIndexSchema);\n if (result.success) {\n summaries = result.data as CompactedSummary[];\n }\n }\n } catch {\n summaries = [];\n }\n \n summaries.push(summary);\n \n // Keep only last 12 summaries (1 year of monthly summaries)\n if (summaries.length > 12) {\n summaries = summaries.slice(-12);\n }\n \n // Create backup before writing\n const backupManager = new BackupManager(summaryPath);\n await backupManager.createBackup();\n \n // Atomic write\n await atomicWriteJSON(summaryPath, summaries);\n}\n\n/**\n * Load compacted summaries with validation and auto-recovery\n */\nexport async function loadCompactedSummaries(projectDir: string): Promise<CompactedSummary[]> {\n const summaryPath = join(getTrieDirectory(projectDir), 'memory', 'compacted-summaries.json');\n \n try {\n if (existsSync(summaryPath)) {\n const content = await readFile(summaryPath, 'utf-8');\n const result = safeParseAndValidate(content, CompactedSummariesIndexSchema);\n \n if (result.success) {\n return result.data as CompactedSummary[];\n }\n \n // Validation failed - attempt recovery\n const backupManager = new BackupManager(summaryPath);\n if (await backupManager.recoverFromBackup()) {\n const recovered = await readFile(summaryPath, 'utf-8');\n const recoveredResult = safeParseAndValidate(recovered, CompactedSummariesIndexSchema);\n if (recoveredResult.success) {\n return recoveredResult.data as CompactedSummary[];\n }\n }\n }\n } catch {\n // File doesn't exist or recovery failed\n }\n \n return [];\n}\n\n/**\n * Generate a markdown summary of compacted history\n */\nexport function formatCompactedSummary(summary: CompactedSummary): string {\n const lines: string[] = [\n `## Compacted Summary: ${summary.period}`,\n '',\n `**Total Issues:** ${summary.totalIssues} (${summary.resolvedCount} resolved)`,\n '',\n '### By Severity',\n ...Object.entries(summary.bySeverity).map(([s, c]) => `- ${s}: ${c}`),\n '',\n '### Top Patterns',\n ...summary.topPatterns.slice(0, 5).map(p => \n `- **${p.pattern.slice(0, 50)}...** (${p.count}x, ${p.severity})`\n ),\n '',\n '### Hot Files',\n ...summary.hotFiles.slice(0, 5).map(f => `- ${f.file}: ${f.count} issues`),\n ];\n \n return lines.join('\\n');\n}\n\n/**\n * Get insights from compacted history\n */\nexport async function getHistoricalInsights(projectDir: string): Promise<{\n totalHistoricalIssues: number;\n recurringPatterns: PatternSummary[];\n improvementTrend: 'improving' | 'stable' | 'declining' | 'unknown';\n}> {\n const summaries = await loadCompactedSummaries(projectDir);\n \n if (summaries.length === 0) {\n return {\n totalHistoricalIssues: 0,\n recurringPatterns: [],\n improvementTrend: 'unknown',\n };\n }\n \n const totalHistoricalIssues = summaries.reduce((sum, s) => sum + s.totalIssues, 0);\n \n // Find patterns that appear across multiple summaries\n const patternCounts: Map<string, PatternSummary & { appearances: number }> = new Map();\n \n for (const summary of summaries) {\n for (const pattern of summary.topPatterns) {\n const key = pattern.pattern;\n const existing = patternCounts.get(key);\n if (existing) {\n existing.count += pattern.count;\n existing.appearances++;\n } else {\n patternCounts.set(key, { ...pattern, appearances: 1 });\n }\n }\n }\n \n const recurringPatterns = Array.from(patternCounts.values())\n .filter(p => p.appearances >= 2)\n .sort((a, b) => b.count - a.count)\n .slice(0, 5);\n \n // Calculate improvement trend\n let improvementTrend: 'improving' | 'stable' | 'declining' | 'unknown' = 'unknown';\n \n if (summaries.length >= 2) {\n const recent = summaries.slice(-2);\n const olderCount = recent[0]?.totalIssues || 0;\n const newerCount = recent[1]?.totalIssues || 0;\n \n if (newerCount < olderCount * 0.8) {\n improvementTrend = 'improving';\n } else if (newerCount > olderCount * 1.2) {\n improvementTrend = 'declining';\n } else {\n improvementTrend = 'stable';\n }\n }\n \n return {\n totalHistoricalIssues,\n recurringPatterns,\n improvementTrend,\n };\n}\n","/**\n * Atomic File Write Utility\n * \n * Provides safe file writes using the temp file + rename pattern.\n * Prevents data corruption from interrupted writes or crashes.\n * \n * Pattern:\n * 1. Write to a temporary file with random suffix\n * 2. Rename temp file to target path (atomic on POSIX systems)\n * 3. Clean up temp file on failure\n */\n\nimport { writeFile, rename, unlink, mkdir } from 'fs/promises';\nimport { randomBytes } from 'crypto';\nimport { dirname } from 'path';\n\nexport interface AtomicWriteOptions {\n /**\n * Create parent directories if they don't exist\n * @default true\n */\n createDir?: boolean;\n \n /**\n * File encoding for string data\n * @default 'utf-8'\n */\n encoding?: BufferEncoding;\n}\n\n/**\n * Write data to a file atomically\n * \n * Uses a temp file + rename pattern to ensure the target file\n * is never in a partially written state. On POSIX systems,\n * rename() is atomic, so readers will always see either the\n * old complete file or the new complete file.\n * \n * @param filePath - Target file path\n * @param data - Data to write (string or Buffer)\n * @param options - Write options\n * @throws Error if write or rename fails\n * \n * @example\n * ```typescript\n * await atomicWriteFile('/path/to/data.json', JSON.stringify(data, null, 2));\n * ```\n */\nexport async function atomicWriteFile(\n filePath: string,\n data: string | Buffer,\n options: AtomicWriteOptions = {}\n): Promise<void> {\n const { createDir = true, encoding = 'utf-8' } = options;\n \n // Generate a unique temp file path\n const tempSuffix = randomBytes(6).toString('hex');\n const tempPath = `${filePath}.${tempSuffix}.tmp`;\n \n try {\n // Ensure parent directory exists\n if (createDir) {\n await mkdir(dirname(filePath), { recursive: true });\n }\n \n // Write to temp file\n if (typeof data === 'string') {\n await writeFile(tempPath, data, { encoding });\n } else {\n await writeFile(tempPath, data);\n }\n \n // Atomic rename to target path\n await rename(tempPath, filePath);\n } catch (error) {\n // Clean up temp file on failure\n try {\n await unlink(tempPath);\n } catch {\n // Ignore cleanup errors - temp file might not exist\n }\n throw error;\n }\n}\n\n/**\n * Write JSON data to a file atomically\n * \n * Convenience wrapper that handles JSON serialization\n * with optional pretty printing.\n * \n * @param filePath - Target file path\n * @param data - Data to serialize as JSON\n * @param options - Write options and JSON formatting\n * @throws Error if serialization, write, or rename fails\n * \n * @example\n * ```typescript\n * await atomicWriteJSON('/path/to/config.json', { key: 'value' });\n * ```\n */\nexport async function atomicWriteJSON(\n filePath: string,\n data: unknown,\n options: AtomicWriteOptions & {\n /**\n * Spaces for JSON pretty printing\n * @default 2\n */\n spaces?: number;\n } = {}\n): Promise<void> {\n const { spaces = 2, ...writeOptions } = options;\n const json = JSON.stringify(data, null, spaces);\n await atomicWriteFile(filePath, json, writeOptions);\n}\n","/**\n * Backup Manager\n * \n * Maintains rotational backups of critical data files.\n * Provides automatic recovery from corrupted files.\n * \n * Features:\n * - N rotational backups (default: 5)\n * - Automatic pruning of old backups\n * - Validation before recovery\n * - Timestamp-based backup naming\n */\n\nimport { copyFile, readdir, unlink, readFile, stat } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { dirname, basename, join } from 'path';\n\nexport interface BackupOptions {\n /**\n * Maximum number of backups to keep\n * @default 5\n */\n maxBackups?: number;\n \n /**\n * Custom validator function for backup validation\n * Returns true if the backup is valid\n */\n validator?: (content: string) => boolean;\n}\n\nexport interface BackupInfo {\n path: string;\n timestamp: number;\n size: number;\n}\n\n/**\n * Manages rotational backups for a file\n * \n * @example\n * ```typescript\n * const manager = new BackupManager('/path/to/issues.json');\n * \n * // Create backup before modifying\n * await manager.createBackup();\n * \n * // If corruption detected, recover\n * if (await manager.recoverFromBackup()) {\n * console.log('Recovered from backup');\n * }\n * ```\n */\nexport class BackupManager {\n private readonly filePath: string;\n private readonly maxBackups: number;\n private readonly validator: ((content: string) => boolean) | undefined;\n private readonly backupDir: string;\n private readonly baseFileName: string;\n\n constructor(filePath: string, options: BackupOptions = {}) {\n this.filePath = filePath;\n this.maxBackups = options.maxBackups ?? 5;\n this.validator = options.validator;\n this.backupDir = dirname(filePath);\n this.baseFileName = basename(filePath);\n }\n\n /**\n * Create a backup of the current file\n * \n * @returns The backup file path, or null if source doesn't exist\n */\n async createBackup(): Promise<string | null> {\n if (!existsSync(this.filePath)) {\n return null;\n }\n\n const timestamp = Date.now();\n const backupPath = this.getBackupPath(timestamp);\n\n await copyFile(this.filePath, backupPath);\n await this.pruneOldBackups();\n\n return backupPath;\n }\n\n /**\n * List all backups sorted by timestamp (newest first)\n */\n async listBackups(): Promise<BackupInfo[]> {\n if (!existsSync(this.backupDir)) {\n return [];\n }\n\n const files = await readdir(this.backupDir);\n const backupPattern = new RegExp(\n `^${this.escapeRegex(this.baseFileName)}\\\\.backup\\\\.(\\\\d+)$`\n );\n\n const backups: BackupInfo[] = [];\n\n for (const file of files) {\n const match = file.match(backupPattern);\n if (match) {\n const timestamp = parseInt(match[1]!, 10);\n const backupPath = join(this.backupDir, file);\n \n try {\n const stats = await stat(backupPath);\n backups.push({\n path: backupPath,\n timestamp,\n size: stats.size,\n });\n } catch {\n // Skip files we can't stat\n }\n }\n }\n\n // Sort by timestamp, newest first\n return backups.sort((a, b) => b.timestamp - a.timestamp);\n }\n\n /**\n * Find the first valid backup\n * \n * Iterates through backups from newest to oldest,\n * returning the first one that passes validation.\n * \n * @returns Path to valid backup, or null if none found\n */\n async findValidBackup(): Promise<string | null> {\n const backups = await this.listBackups();\n\n for (const backup of backups) {\n if (await this.validateBackup(backup.path)) {\n return backup.path;\n }\n }\n\n return null;\n }\n\n /**\n * Validate a backup file\n * \n * If a custom validator was provided, uses that.\n * Otherwise, attempts JSON parse for .json files.\n * \n * @returns true if backup is valid\n */\n async validateBackup(backupPath: string): Promise<boolean> {\n try {\n const content = await readFile(backupPath, 'utf-8');\n\n // Use custom validator if provided\n if (this.validator) {\n return this.validator(content);\n }\n\n // Default validation: check if it's valid JSON for .json files\n if (this.filePath.endsWith('.json')) {\n JSON.parse(content);\n return true;\n }\n\n // For non-JSON files, just check it's readable\n return content.length > 0;\n } catch {\n return false;\n }\n }\n\n /**\n * Recover from the most recent valid backup\n * \n * @returns true if recovery was successful\n */\n async recoverFromBackup(): Promise<boolean> {\n const validBackup = await this.findValidBackup();\n \n if (!validBackup) {\n return false;\n }\n\n await copyFile(validBackup, this.filePath);\n return true;\n }\n\n /**\n * Remove old backups beyond the max limit\n */\n private async pruneOldBackups(): Promise<void> {\n const backups = await this.listBackups();\n\n // Remove backups beyond the limit\n const toRemove = backups.slice(this.maxBackups);\n \n for (const backup of toRemove) {\n try {\n await unlink(backup.path);\n } catch {\n // Ignore errors - backup might already be removed\n }\n }\n }\n\n /**\n * Get the backup path for a given timestamp\n */\n private getBackupPath(timestamp: number): string {\n return join(this.backupDir, `${this.baseFileName}.backup.${timestamp}`);\n }\n\n /**\n * Escape special regex characters in a string\n */\n private escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n }\n\n /**\n * Get the number of existing backups\n */\n async getBackupCount(): Promise<number> {\n const backups = await this.listBackups();\n return backups.length;\n }\n\n /**\n * Get the most recent backup timestamp\n */\n async getLatestBackupTime(): Promise<number | null> {\n const backups = await this.listBackups();\n return backups[0]?.timestamp ?? null;\n }\n\n /**\n * Delete all backups\n */\n async clearBackups(): Promise<number> {\n const backups = await this.listBackups();\n let deleted = 0;\n\n for (const backup of backups) {\n try {\n await unlink(backup.path);\n deleted++;\n } catch {\n // Ignore errors\n }\n }\n\n return deleted;\n }\n}\n\n/**\n * Default JSON validator\n * \n * Validates that content is valid JSON and optionally\n * checks for required fields.\n */\nexport function createJSONValidator(requiredFields?: string[]): (content: string) => boolean {\n return (content: string): boolean => {\n try {\n const parsed = JSON.parse(content);\n \n if (requiredFields && Array.isArray(parsed)) {\n // For arrays, check first element has required fields\n if (parsed.length > 0) {\n const first = parsed[0];\n return requiredFields.every(field => field in first);\n }\n // Empty array is valid\n return true;\n }\n \n if (requiredFields && typeof parsed === 'object' && parsed !== null) {\n return requiredFields.every(field => field in parsed);\n }\n \n return true;\n } catch {\n return false;\n }\n };\n}\n","/**\n * Memory Validation\n * \n * Schema validation for memory storage files using Zod.\n * Catches corruption early and provides clear error messages.\n * \n * Used by:\n * - issue-store.ts for issues.json\n * - global-memory.ts for global-patterns.json\n * - compactor.ts for compacted-summaries.json\n */\n\nimport { z } from 'zod';\n\n// ============================================================================\n// Issue Schemas\n// ============================================================================\n\n/**\n * Schema for a stored issue in issues.json\n */\nexport const StoredIssueSchema = z.object({\n id: z.string(),\n hash: z.string(),\n severity: z.string(),\n issue: z.string(),\n fix: z.string(),\n file: z.string(),\n line: z.number().optional(),\n agent: z.string(),\n category: z.string().optional(),\n timestamp: z.string(),\n project: z.string(),\n resolved: z.boolean().optional(),\n resolvedAt: z.string().optional(),\n});\n\nexport type ValidatedStoredIssue = z.infer<typeof StoredIssueSchema>;\n\n/**\n * Schema for the issues.json file (array of issues)\n */\nexport const IssueIndexSchema = z.array(StoredIssueSchema);\n\n// ============================================================================\n// Global Pattern Schemas\n// ============================================================================\n\n/**\n * Schema for a fix applied record\n */\nexport const FixAppliedSchema = z.object({\n project: z.string(),\n timestamp: z.string(),\n fix: z.string(),\n});\n\n/**\n * Schema for a global pattern in global-patterns.json\n */\nexport const GlobalPatternSchema = z.object({\n id: z.string(),\n pattern: z.string(),\n description: z.string(),\n severity: z.string(),\n agent: z.string(),\n occurrences: z.number(),\n projects: z.array(z.string()),\n firstSeen: z.string(),\n lastSeen: z.string(),\n fixApplied: FixAppliedSchema.optional(),\n});\n\nexport type ValidatedGlobalPattern = z.infer<typeof GlobalPatternSchema>;\n\n/**\n * Schema for global-patterns.json (array of patterns)\n */\nexport const GlobalPatternsIndexSchema = z.array(GlobalPatternSchema);\n\n// ============================================================================\n// Project Summary Schemas\n// ============================================================================\n\n/**\n * Schema for a project summary\n */\nexport const ProjectSummarySchema = z.object({\n name: z.string(),\n path: z.string(),\n lastScan: z.string(),\n healthScore: z.number(),\n totalIssues: z.number(),\n patterns: z.array(z.string()),\n});\n\nexport type ValidatedProjectSummary = z.infer<typeof ProjectSummarySchema>;\n\n// ============================================================================\n// Compacted Summary Schemas\n// ============================================================================\n\n/**\n * Schema for a pattern summary in compacted data\n */\nexport const PatternSummarySchema = z.object({\n pattern: z.string(),\n count: z.number(),\n severity: z.string(),\n agent: z.string(),\n exampleFix: z.string(),\n});\n\n/**\n * Schema for a hot file entry\n */\nexport const HotFileSchema = z.object({\n file: z.string(),\n count: z.number(),\n});\n\n/**\n * Schema for a compacted summary\n */\nexport const CompactedSummarySchema = z.object({\n period: z.string(),\n startDate: z.string(),\n endDate: z.string(),\n totalIssues: z.number(),\n resolvedCount: z.number(),\n bySeverity: z.record(z.string(), z.number()),\n byAgent: z.record(z.string(), z.number()),\n topPatterns: z.array(PatternSummarySchema),\n hotFiles: z.array(HotFileSchema),\n compactedAt: z.string(),\n});\n\nexport type ValidatedCompactedSummary = z.infer<typeof CompactedSummarySchema>;\n\n/**\n * Schema for compacted-summaries.json (array of summaries)\n */\nexport const CompactedSummariesIndexSchema = z.array(CompactedSummarySchema);\n\n// ============================================================================\n// Validation Error\n// ============================================================================\n\n/**\n * Custom error for validation failures\n */\nexport class ValidationError extends Error {\n constructor(\n message: string,\n public readonly zodError: z.ZodError,\n public readonly filePath?: string\n ) {\n super(message);\n this.name = 'ValidationError';\n }\n\n /**\n * Get a human-readable summary of validation errors\n */\n getSummary(): string {\n const issues = this.zodError.issues.slice(0, 5);\n const lines = issues.map(issue => {\n const path = issue.path.join('.');\n return ` - ${path}: ${issue.message}`;\n });\n \n if (this.zodError.issues.length > 5) {\n lines.push(` ... and ${this.zodError.issues.length - 5} more errors`);\n }\n \n return lines.join('\\n');\n }\n}\n\n// ============================================================================\n// Validation Functions\n// ============================================================================\n\n/**\n * Validate issue index data\n * \n * @throws ValidationError if data is invalid\n * @returns Validated issue array\n */\nexport function validateIssueIndex(\n data: unknown,\n filePath?: string\n): ValidatedStoredIssue[] {\n const result = IssueIndexSchema.safeParse(data);\n \n if (!result.success) {\n throw new ValidationError(\n `Issue index validation failed${filePath ? ` (${filePath})` : ''}`,\n result.error,\n filePath\n );\n }\n \n return result.data;\n}\n\n/**\n * Validate global patterns data\n * \n * @throws ValidationError if data is invalid\n * @returns Validated patterns array\n */\nexport function validateGlobalPatterns(\n data: unknown,\n filePath?: string\n): ValidatedGlobalPattern[] {\n const result = GlobalPatternsIndexSchema.safeParse(data);\n \n if (!result.success) {\n throw new ValidationError(\n `Global patterns validation failed${filePath ? ` (${filePath})` : ''}`,\n result.error,\n filePath\n );\n }\n \n return result.data;\n}\n\n/**\n * Validate project summary data\n * \n * @throws ValidationError if data is invalid\n * @returns Validated project summary\n */\nexport function validateProjectSummary(\n data: unknown,\n filePath?: string\n): ValidatedProjectSummary {\n const result = ProjectSummarySchema.safeParse(data);\n \n if (!result.success) {\n throw new ValidationError(\n `Project summary validation failed${filePath ? ` (${filePath})` : ''}`,\n result.error,\n filePath\n );\n }\n \n return result.data;\n}\n\n/**\n * Validate compacted summaries data\n * \n * @throws ValidationError if data is invalid\n * @returns Validated summaries array\n */\nexport function validateCompactedSummaries(\n data: unknown,\n filePath?: string\n): ValidatedCompactedSummary[] {\n const result = CompactedSummariesIndexSchema.safeParse(data);\n \n if (!result.success) {\n throw new ValidationError(\n `Compacted summaries validation failed${filePath ? ` (${filePath})` : ''}`,\n result.error,\n filePath\n );\n }\n \n return result.data;\n}\n\n/**\n * Safely parse and validate JSON\n * \n * Combines JSON parsing with schema validation.\n * Returns null on any error instead of throwing.\n */\nexport function safeParseAndValidate<T>(\n content: string,\n schema: z.ZodSchema<T>\n): { success: true; data: T } | { success: false; error: string } {\n try {\n const parsed = JSON.parse(content);\n const result = schema.safeParse(parsed);\n \n if (result.success) {\n return { success: true, data: result.data };\n }\n \n return {\n success: false,\n error: `Validation failed: ${result.error.issues[0]?.message || 'Unknown error'}`,\n };\n } catch (error) {\n return {\n success: false,\n error: `JSON parse failed: ${error instanceof Error ? error.message : 'Unknown error'}`,\n };\n }\n}\n\n/**\n * Check if data matches a schema (non-throwing)\n */\nexport function isValidSchema<T>(data: unknown, schema: z.ZodSchema<T>): boolean {\n return schema.safeParse(data).success;\n}\n","import { createHash } from 'crypto';\nimport { mkdir, readFile } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { getWorkingDirectory, getTrieDirectory } from '../utils/workspace.js';\nimport type { StoredIssue } from './issue-store.js';\n\nconst LEDGER_FILENAME = 'ledger.json';\nconst GENESIS_HASH = '0'.repeat(64);\nconst LEDGER_VERSION = 1;\n\nexport interface LedgerEntry {\n id: string;\n hash: string;\n severity: string;\n file: string;\n agent: string;\n timestamp: string;\n}\n\nexport interface LedgerBlock {\n version: number;\n date: string;\n entries: LedgerEntry[];\n previousHash: string;\n merkleRoot: string;\n blockHash: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface LedgerVerificationResult {\n valid: boolean;\n error?: string;\n}\n\nexport async function appendIssuesToLedger(\n issues: StoredIssue[],\n workDir?: string\n): Promise<LedgerBlock | null> {\n if (issues.length === 0) return null;\n\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n\n const blocks = await loadLedger(projectDir);\n const today = new Date().toISOString().slice(0, 10);\n const now = new Date().toISOString();\n\n const entries: LedgerEntry[] = issues.map(issue => ({\n id: issue.id,\n hash: issue.hash,\n severity: issue.severity,\n file: issue.file,\n agent: issue.agent,\n timestamp: issue.timestamp,\n }));\n\n const previousBlock = blocks[blocks.length - 1];\n const block = previousBlock && previousBlock.date === today\n ? previousBlock\n : createBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH);\n\n if (block !== previousBlock) {\n blocks.push(block);\n }\n\n block.entries = [...block.entries, ...entries];\n block.merkleRoot = computeMerkleRoot(block.entries.map(entry => entry.hash));\n block.blockHash = computeBlockHash(block.previousHash, block.merkleRoot, block.date, block.version);\n block.updatedAt = now;\n\n await saveLedger(blocks, projectDir);\n return block;\n}\n\nexport async function verifyLedger(workDir?: string): Promise<LedgerVerificationResult> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const blocks = await loadLedger(projectDir);\n\n if (blocks.length === 0) {\n return { valid: true };\n }\n\n for (let i = 0; i < blocks.length; i += 1) {\n const block = blocks[i];\n if (!block) {\n return { valid: false, error: `Block ${i} missing` };\n }\n const expectedPreviousHash = i === 0\n ? GENESIS_HASH\n : blocks[i - 1]?.blockHash;\n\n if (!expectedPreviousHash) {\n return { valid: false, error: `Block ${i} missing previous block` };\n }\n\n if (block.previousHash !== expectedPreviousHash) {\n return { valid: false, error: `Block ${i} previous hash mismatch` };\n }\n\n const computedMerkleRoot = computeMerkleRoot(block.entries.map(entry => entry.hash));\n if (block.merkleRoot !== computedMerkleRoot) {\n return { valid: false, error: `Block ${i} merkle root mismatch` };\n }\n\n const computedBlockHash = computeBlockHash(block.previousHash, block.merkleRoot, block.date, block.version);\n if (block.blockHash !== computedBlockHash) {\n return { valid: false, error: `Block ${i} hash mismatch` };\n }\n }\n\n return { valid: true };\n}\n\nexport function computeMerkleRoot(hashes: string[]): string {\n if (hashes.length === 0) {\n return sha256('');\n }\n\n let level = hashes.slice();\n while (level.length > 1) {\n const nextLevel: string[] = [];\n for (let i = 0; i < level.length; i += 2) {\n const left = level[i];\n const right = level[i + 1] ?? left;\n nextLevel.push(sha256(`${left}:${right}`));\n }\n level = nextLevel;\n }\n\n return level[0]!;\n}\n\nfunction computeBlockHash(previousHash: string, merkleRoot: string, date: string, version: number): string {\n return sha256(`${version}:${date}:${previousHash}:${merkleRoot}`);\n}\n\nfunction createBlock(date: string, now: string, previousHash: string): LedgerBlock {\n return {\n version: LEDGER_VERSION,\n date,\n entries: [],\n previousHash,\n merkleRoot: '',\n blockHash: '',\n createdAt: now,\n updatedAt: now,\n };\n}\n\nasync function loadLedger(projectDir: string): Promise<LedgerBlock[]> {\n const ledgerPath = join(getTrieDirectory(projectDir), 'memory', LEDGER_FILENAME);\n try {\n if (!existsSync(ledgerPath)) return [];\n const content = await readFile(ledgerPath, 'utf-8');\n const parsed = JSON.parse(content);\n if (!Array.isArray(parsed)) return [];\n return parsed as LedgerBlock[];\n } catch {\n return [];\n }\n}\n\nasync function saveLedger(blocks: LedgerBlock[], projectDir: string): Promise<void> {\n const ledgerPath = join(getTrieDirectory(projectDir), 'memory', LEDGER_FILENAME);\n await atomicWriteJSON(ledgerPath, blocks);\n}\n\nfunction sha256(input: string): string {\n return createHash('sha256').update(input).digest('hex');\n}\n"],"mappings":"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","names":["mkdir","writeFile","readFile","readdir","createHash","existsSync","join","mkdir","readFile","existsSync","join","unlink","dirname","join","mkdir","existsSync","readFile","mkdir","readFile","existsSync","join","join","mkdir","join","existsSync","readFile","join","mkdir","existsSync","readdir","readFile","writeFile","createHash"]}
|
|
@@ -6,10 +6,13 @@ import {
|
|
|
6
6
|
} from "./chunk-SH2JIQLB.js";
|
|
7
7
|
import {
|
|
8
8
|
tryGetClient
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-GMKPXL4Q.js";
|
|
10
10
|
import {
|
|
11
11
|
searchIssues
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-JG2TAVAO.js";
|
|
13
|
+
import {
|
|
14
|
+
getTrieDirectory
|
|
15
|
+
} from "./chunk-D5VEUZLP.js";
|
|
13
16
|
|
|
14
17
|
// src/guardian/gotcha-predictor.ts
|
|
15
18
|
import fs from "fs";
|
|
@@ -152,7 +155,7 @@ var ContextStore = class {
|
|
|
152
155
|
db;
|
|
153
156
|
dbFilePath;
|
|
154
157
|
constructor(projectPath, dbFilePath) {
|
|
155
|
-
this.dbFilePath = dbFilePath ?? path2.join(projectPath, "
|
|
158
|
+
this.dbFilePath = dbFilePath ?? path2.join(getTrieDirectory(projectPath), "context.db");
|
|
156
159
|
this.ensureDirectory();
|
|
157
160
|
this.db = new Database(this.dbFilePath);
|
|
158
161
|
this.configure();
|
|
@@ -530,4 +533,4 @@ export {
|
|
|
530
533
|
GotchaPredictor,
|
|
531
534
|
ContextGraph
|
|
532
535
|
};
|
|
533
|
-
//# sourceMappingURL=chunk-
|
|
536
|
+
//# sourceMappingURL=chunk-OXZKSR6J.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/guardian/gotcha-predictor.ts","../src/context/graph.ts","../src/context/store.ts"],"sourcesContent":["import { ContextGraph } from '../context/graph.js';\nimport { searchIssues } from '../memory/issue-store.js';\nimport { scanForVulnerabilities } from '../trie/vulnerability-signatures.js';\nimport { scanForVibeCodeIssues } from '../trie/vibe-code-signatures.js';\nimport type { LinearTicketNode, LinearTicketNodeData } from '../context/nodes.js';\nimport { tryGetClient } from '../ai/client.js';\nimport fs from 'node:fs';\nimport path from 'node:path';\n\nexport interface GotchaPrediction {\n id: string;\n message: string;\n confidence: number;\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n precedentId?: string;\n recommendation: string;\n evidence: {\n pastIncidents: string[];\n matchingPatterns: string[];\n relatedTickets: string[];\n };\n}\n\nexport class GotchaPredictor {\n private readonly projectPath: string;\n private readonly graph: ContextGraph;\n\n constructor(projectPath: string, graph: ContextGraph) {\n this.projectPath = projectPath;\n this.graph = graph;\n }\n\n async predictGotchas(changedFiles: string[]): Promise<GotchaPrediction[]> {\n const gotchas: GotchaPrediction[] = [];\n\n // 1. Get active Linear tickets\n const tickets = (await this.graph.listNodes()).filter(n => n.type === 'linear-ticket') as LinearTicketNode[];\n \n for (const file of changedFiles) {\n const fileGotchas = await this.predictForFile(file, tickets);\n gotchas.push(...fileGotchas);\n }\n\n return gotchas;\n }\n\n private async predictForFile(filePath: string, tickets: LinearTicketNode[]): Promise<GotchaPrediction[]> {\n const gotchas: GotchaPrediction[] = [];\n const fullPath = path.resolve(this.projectPath, filePath);\n\n if (!fs.existsSync(fullPath)) return [];\n\n const content = fs.readFileSync(fullPath, 'utf-8');\n\n // 1. Run deterministic scanners for signatures\n const vulnerabilities = await scanForVulnerabilities(content, filePath);\n const vibeIssues = await scanForVibeCodeIssues(content, filePath);\n\n const signatures = [\n ...vulnerabilities.map(v => v.category),\n ...vibeIssues.map(v => v.category)\n ];\n\n for (const ticket of tickets) {\n const ticketData = ticket.data as LinearTicketNodeData;\n \n // Correlation 1: Ticket Intent vs Deterministic Signatures\n const intentMatch = this.correlateIntentWithSignatures(ticketData, signatures);\n if (intentMatch) {\n gotchas.push(intentMatch);\n }\n\n // Correlation 2: Historical Precedents\n const historicalPrecedents = await this.findHistoricalPrecedents(filePath, ticketData);\n if (historicalPrecedents) {\n gotchas.push(historicalPrecedents);\n }\n }\n\n return gotchas;\n }\n\n private correlateIntentWithSignatures(ticket: LinearTicketNodeData, signatures: string[]): GotchaPrediction | null {\n const relevantSignatures = signatures.filter(sig => \n ticket.intentVibe.some(vibe => this.vibeToSignatureMap(vibe).includes(sig))\n );\n\n if (relevantSignatures.length > 0) {\n return {\n id: `gotcha-intent-${ticket.ticketId}-${Date.now()}`,\n message: `[${ticket.ticketId}] Working on \"${ticket.title}\" (${ticket.intentVibe.join(', ')}) in a file with ${relevantSignatures.join(', ')} signatures.`,\n confidence: 0.8,\n riskLevel: 'high',\n recommendation: `Be careful with ${relevantSignatures[0]} patterns as they correlate with the intent of your ticket.`,\n evidence: {\n pastIncidents: [],\n matchingPatterns: relevantSignatures,\n relatedTickets: [ticket.ticketId]\n }\n };\n }\n\n return null;\n }\n\n private async findHistoricalPrecedents(filePath: string, ticket: LinearTicketNodeData): Promise<GotchaPrediction | null> {\n // Search for historical issues similar to this ticket's description\n const similarIssues = await searchIssues(ticket.description, {\n workDir: this.projectPath,\n limit: 3\n });\n\n const relevantIssues = similarIssues.filter(r => r.issue.file === filePath || r.issue.file.includes(path.basename(filePath)));\n\n const [firstMatch] = relevantIssues;\n if (firstMatch) {\n const issue = firstMatch.issue;\n return {\n id: `gotcha-precedent-${ticket.ticketId}-${Date.now()}`,\n message: `A similar task in the past caused an issue: \"${issue.issue}\"`,\n confidence: 0.9,\n riskLevel: 'critical',\n precedentId: issue.id,\n recommendation: `Last time we worked on something similar here, we had to fix: \"${issue.fix}\". Check this first.`,\n evidence: {\n pastIncidents: [issue.id],\n matchingPatterns: [],\n relatedTickets: [ticket.ticketId]\n }\n };\n }\n\n return null;\n }\n\n private vibeToSignatureMap(vibe: string): string[] {\n const map: Record<string, string[]> = {\n 'performance': ['giant-file', 'performance', 'react-antipattern'],\n 'security': ['injection', 'secrets', 'auth', 'xss', 'crypto'],\n 'auth': ['auth', 'secrets', 'config'],\n 'bug': ['no-error-handling', 'async', 'error-handling'],\n 'feature': ['mixing-concerns', 'hardcoded'],\n 'refactor': ['code-smell', 'giant-file', 'mixing-concerns']\n };\n return map[vibe] || [];\n }\n\n async synthesizeGotchaExplanation(gotcha: GotchaPrediction): Promise<string> {\n const client = tryGetClient();\n if (!client) return gotcha.message;\n\n const prompt = `\n You are a JIT Defect Predictor. You found a potential \"gotcha\" for a developer.\n \n Ticket context: ${gotcha.evidence.relatedTickets.join(', ')}\n Signatures detected: ${gotcha.evidence.matchingPatterns.join(', ')}\n Past incidents: ${gotcha.evidence.pastIncidents.join(', ')}\n \n Raw message: ${gotcha.message}\n Recommendation: ${gotcha.recommendation}\n \n Explain this gotcha in a concise, human-friendly way (max 2 sentences). \n Make it sound like a senior dev giving a helpful nudge.\n `;\n\n try {\n const response = await client.messages.create({\n model: 'claude-3-5-sonnet-20240620',\n max_tokens: 100,\n messages: [{ role: 'user', content: prompt }]\n });\n\n const text = response.content\n .filter((block): block is { type: 'text'; text: string } => block.type === 'text')\n .map(block => block.text)\n .join('');\n \n return text.trim() || gotcha.message;\n } catch {\n return gotcha.message;\n }\n }\n}\n","import crypto from 'node:crypto';\nimport path from 'node:path';\n\nimport type { RiskLevel } from '../types/index.js';\nimport { ContextStore } from './store.js';\nimport type {\n ChangeNode,\n ChangeNodeData,\n ContextSnapshot,\n DecisionNode,\n DecisionNodeData,\n Edge,\n EdgeDirection,\n EdgeType,\n FileNode,\n FileNodeData,\n FixNode,\n FixNodeData,\n IncidentNode,\n IncidentNodeData,\n IssueNode,\n IssueNodeData,\n LinearTicketNode,\n LinearTicketNodeData,\n Node,\n NodeData,\n NodeType,\n PatternNode,\n PatternNodeData\n} from './types.js';\n\nexport class ContextGraph {\n private readonly store: ContextStore;\n private readonly projectPath: string;\n\n constructor(projectPath: string, dbPath?: string, store?: ContextStore) {\n this.projectPath = projectPath;\n this.store = store ?? new ContextStore(projectPath, dbPath);\n }\n\n get projectRoot(): string {\n return this.projectPath;\n }\n\n async addNode(type: 'file', data: FileNodeData): Promise<FileNode>;\n async addNode(type: 'change', data: ChangeNodeData): Promise<ChangeNode>;\n async addNode(type: 'incident', data: IncidentNodeData): Promise<IncidentNode>;\n async addNode(type: 'issue', data: IssueNodeData): Promise<IssueNode>;\n async addNode(type: 'pattern', data: PatternNodeData): Promise<PatternNode>;\n async addNode(type: 'fix', data: FixNodeData): Promise<FixNode>;\n async addNode(type: 'decision', data: DecisionNodeData): Promise<DecisionNode>;\n async addNode(type: 'linear-ticket', data: LinearTicketNodeData): Promise<LinearTicketNode>;\n async addNode(type: NodeType, data: NodeData): Promise<Node> {\n const now = new Date().toISOString();\n const id = this.generateNodeId(type, data);\n const node = {\n id,\n type,\n data,\n created_at: now,\n updated_at: now\n } as Node;\n\n this.store.addNode(node);\n return node;\n }\n\n async getNode(type: NodeType, id: string): Promise<Node | null> {\n return this.store.getNodeByType(type, id);\n }\n\n async updateNode(type: NodeType, id: string, updates: Partial<NodeData>): Promise<void> {\n const updated = this.store.updateNode(id, updates, new Date().toISOString());\n if (updated && updated.type !== type) {\n throw new Error(`Type mismatch for node ${id}: expected ${type} but found ${updated.type}`);\n }\n }\n\n async deleteNode(_type: NodeType, id: string): Promise<void> {\n this.store.deleteNode(id);\n }\n\n async addEdge(\n fromId: string,\n toId: string,\n type: EdgeType,\n metadata: Record<string, unknown> = {},\n weight = 1\n ): Promise<Edge> {\n const edge: Edge = {\n id: crypto.randomUUID(),\n from_id: fromId,\n to_id: toId,\n type,\n weight,\n metadata,\n created_at: new Date().toISOString()\n };\n\n this.store.addEdge(edge);\n return edge;\n }\n\n async getEdges(nodeId: string, direction: EdgeDirection = 'both'): Promise<Edge[]> {\n return this.store.getEdges(nodeId, direction);\n }\n\n async getIncidentsForFile(filePath: string): Promise<IncidentNode[]> {\n const fileNode = this.findFileNode(filePath);\n if (!fileNode) return [];\n\n const incidents = new Map<string, IncidentNode>();\n\n const affectEdges = this.store.getEdges(fileNode.id, 'in').filter((edge) => edge.type === 'affects');\n for (const edge of affectEdges) {\n const changeId = edge.from_id;\n const leadEdges = this.store.getEdges(changeId, 'out').filter((e) => e.type === 'leadTo');\n const causedByEdges = this.store.getEdges(changeId, 'in').filter((e) => e.type === 'causedBy');\n\n for (const le of leadEdges) {\n const incident = this.store.getNodeByType('incident', le.to_id);\n if (incident) incidents.set(incident.id, incident as IncidentNode);\n }\n\n for (const ce of causedByEdges) {\n const incident = this.store.getNodeByType('incident', ce.from_id);\n if (incident) incidents.set(incident.id, incident as IncidentNode);\n }\n }\n\n return Array.from(incidents.values());\n }\n\n async getPatternsForFile(filePath: string): Promise<PatternNode[]> {\n const normalized = this.normalizePath(filePath);\n const nodes = this.store.findNodesByType('pattern') as PatternNode[];\n\n return nodes.filter((node) =>\n node.data.appliesTo.some((pattern) => normalized.includes(pattern) || filePath.includes(pattern))\n );\n }\n\n async getRecentChanges(limit: number): Promise<ChangeNode[]> {\n const nodes = this.store.findNodesByType('change') as ChangeNode[];\n return nodes\n .sort((a, b) => new Date(b.data.timestamp).getTime() - new Date(a.data.timestamp).getTime())\n .slice(0, limit);\n }\n\n async calculateFileRisk(filePath: string): Promise<RiskLevel> {\n const fileNode = this.findFileNode(filePath);\n if (!fileNode) return 'low';\n\n // Simple heuristic based on incidents and changes\n const incidentScore = Math.min(fileNode.data.incidentCount * 2, 6);\n const changeScore = Math.min(fileNode.data.changeCount, 4);\n const baseScore = this.riskLevelToScore(fileNode.data.riskLevel);\n const total = baseScore + incidentScore + changeScore;\n\n if (total >= 10) return 'critical';\n if (total >= 7) return 'high';\n if (total >= 4) return 'medium';\n return 'low';\n }\n\n async listNodes(): Promise<Node[]> {\n return this.store.listNodes();\n }\n\n async listEdges(): Promise<Edge[]> {\n return this.store.listEdges();\n }\n\n async deleteEdge(id: string): Promise<void> {\n this.store.deleteEdge(id);\n }\n\n async getSnapshot(): Promise<ContextSnapshot> {\n return {\n nodes: this.store.listNodes(),\n edges: this.store.listEdges(),\n exported_at: new Date().toISOString()\n };\n }\n\n async applySnapshot(snapshot: ContextSnapshot): Promise<void> {\n for (const node of snapshot.nodes) {\n const existing = this.store.getNode(node.id);\n if (!existing || this.isNewer(node.updated_at, existing.updated_at)) {\n this.store.upsertNode(node);\n }\n }\n\n for (const edge of snapshot.edges) {\n const existing = this.store.getEdge(edge.id);\n if (!existing) {\n this.store.upsertEdge(edge);\n }\n }\n }\n\n private generateNodeId(type: NodeType, data: NodeData): string {\n if (type === 'file') {\n const fileData = data as FileNodeData;\n return this.normalizePath(fileData.path);\n }\n\n if (type === 'change') {\n const changeData = data as ChangeNodeData;\n if (changeData.commitHash) {\n return changeData.commitHash;\n }\n }\n\n if (type === 'linear-ticket') {\n const ticketData = data as LinearTicketNodeData;\n return `linear:${ticketData.ticketId}`;\n }\n\n return crypto.randomUUID();\n }\n\n private findFileNode(filePath: string): FileNode | null {\n const normalized = this.normalizePath(filePath);\n const nodes = this.store.findNodesByType('file') as FileNode[];\n return (\n nodes.find(\n (node) =>\n node.id === normalized ||\n this.normalizePath(node.data.path) === normalized ||\n node.data.path === filePath\n ) ?? null\n );\n }\n\n private normalizePath(filePath: string): string {\n return path.resolve(this.projectPath, filePath);\n }\n\n private riskLevelToScore(level: RiskLevel): number {\n switch (level) {\n case 'critical':\n return 6;\n case 'high':\n return 4;\n case 'medium':\n return 2;\n default:\n return 0;\n }\n }\n\n private isNewer(incoming: string, existing: string): boolean {\n return new Date(incoming).getTime() >= new Date(existing).getTime();\n }\n}\n","import Database, { type Database as DatabaseType } from 'better-sqlite3';\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport { getTrieDirectory } from '../utils/workspace.js';\n\nimport type { Edge, EdgeDirection, EdgeType, Node, NodeData, NodeType } from './types.js';\n\ntype NodeRow = {\n id: string;\n type: NodeType;\n data: string;\n created_at: string;\n updated_at: string;\n};\n\ntype EdgeRow = {\n id: string;\n from_id: string;\n to_id: string;\n type: EdgeType;\n weight: number;\n metadata: string | null;\n created_at: string;\n};\n\nexport class ContextStore {\n private db: DatabaseType;\n private readonly dbFilePath: string;\n\n constructor(projectPath: string, dbFilePath?: string) {\n this.dbFilePath = dbFilePath ?? path.join(getTrieDirectory(projectPath), 'context.db');\n this.ensureDirectory();\n\n this.db = new Database(this.dbFilePath);\n this.configure();\n this.prepareSchema();\n }\n\n get databasePath(): string {\n return this.dbFilePath;\n }\n\n addNode(node: Node): Node {\n const stmt = this.db.prepare(\n `INSERT INTO nodes (id, type, data, created_at, updated_at)\n VALUES (@id, @type, @data, @created_at, @updated_at)`\n );\n\n stmt.run({\n id: node.id,\n type: node.type,\n data: JSON.stringify(node.data),\n created_at: node.created_at,\n updated_at: node.updated_at\n });\n\n return node;\n }\n\n upsertNode(node: Node): Node {\n const stmt = this.db.prepare(\n `INSERT INTO nodes (id, type, data, created_at, updated_at)\n VALUES (@id, @type, @data, @created_at, @updated_at)\n ON CONFLICT(id) DO UPDATE SET\n type=excluded.type,\n data=excluded.data,\n updated_at=excluded.updated_at`\n );\n\n stmt.run({\n id: node.id,\n type: node.type,\n data: JSON.stringify(node.data),\n created_at: node.created_at,\n updated_at: node.updated_at\n });\n\n return node;\n }\n\n getNode(id: string): Node | null {\n const row = this.db.prepare('SELECT * FROM nodes WHERE id = ?').get(id) as NodeRow | undefined;\n return row ? this.mapNodeRow(row) : null;\n }\n\n getNodeByType(type: NodeType, id: string): Node | null {\n const row = this.db\n .prepare('SELECT * FROM nodes WHERE id = ? AND type = ?')\n .get(id, type) as NodeRow | undefined;\n return row ? this.mapNodeRow(row) : null;\n }\n\n updateNode(id: string, updates: Partial<NodeData>, updatedAt: string): Node | null {\n const existing = this.getNode(id);\n if (!existing) {\n return null;\n }\n\n const merged = {\n ...existing,\n data: { ...existing.data, ...updates },\n updated_at: updatedAt\n } as Node;\n\n this.db\n .prepare(\n `UPDATE nodes SET data = @data, updated_at = @updated_at\n WHERE id = @id`\n )\n .run({\n id,\n data: JSON.stringify(merged.data),\n updated_at: merged.updated_at\n });\n\n return merged;\n }\n\n deleteNode(id: string): void {\n const deleteEdges = this.db.prepare('DELETE FROM edges WHERE from_id = ? OR to_id = ?');\n const deleteNodeStmt = this.db.prepare('DELETE FROM nodes WHERE id = ?');\n\n const transaction = this.db.transaction((nodeId: string) => {\n deleteEdges.run(nodeId, nodeId);\n deleteNodeStmt.run(nodeId);\n });\n\n transaction(id);\n }\n\n listNodes(): Node[] {\n const rows = this.db.prepare('SELECT * FROM nodes').all() as NodeRow[];\n return rows.map((row) => this.mapNodeRow(row));\n }\n\n findNodesByType(type: NodeType): Node[] {\n const rows = this.db.prepare('SELECT * FROM nodes WHERE type = ?').all(type) as NodeRow[];\n return rows.map((row) => this.mapNodeRow(row));\n }\n\n addEdge(edge: Edge): Edge {\n const stmt = this.db.prepare(\n `INSERT INTO edges (id, from_id, to_id, type, weight, metadata, created_at)\n VALUES (@id, @from_id, @to_id, @type, @weight, @metadata, @created_at)`\n );\n\n stmt.run({\n id: edge.id,\n from_id: edge.from_id,\n to_id: edge.to_id,\n type: edge.type,\n weight: edge.weight,\n metadata: JSON.stringify(edge.metadata ?? {}),\n created_at: edge.created_at\n });\n\n return edge;\n }\n\n upsertEdge(edge: Edge): Edge {\n const stmt = this.db.prepare(\n `INSERT INTO edges (id, from_id, to_id, type, weight, metadata, created_at)\n VALUES (@id, @from_id, @to_id, @type, @weight, @metadata, @created_at)\n ON CONFLICT(id) DO UPDATE SET\n from_id=excluded.from_id,\n to_id=excluded.to_id,\n type=excluded.type,\n weight=excluded.weight,\n metadata=excluded.metadata`\n );\n\n stmt.run({\n id: edge.id,\n from_id: edge.from_id,\n to_id: edge.to_id,\n type: edge.type,\n weight: edge.weight,\n metadata: JSON.stringify(edge.metadata ?? {}),\n created_at: edge.created_at\n });\n\n return edge;\n }\n\n getEdge(id: string): Edge | null {\n const row = this.db.prepare('SELECT * FROM edges WHERE id = ?').get(id) as EdgeRow | undefined;\n return row ? this.mapEdgeRow(row) : null;\n }\n\n getEdges(nodeId: string, direction: EdgeDirection = 'both'): Edge[] {\n let rows: EdgeRow[];\n\n if (direction === 'in') {\n rows = this.db.prepare('SELECT * FROM edges WHERE to_id = ?').all(nodeId) as EdgeRow[];\n } else if (direction === 'out') {\n rows = this.db.prepare('SELECT * FROM edges WHERE from_id = ?').all(nodeId) as EdgeRow[];\n } else {\n rows = this.db\n .prepare('SELECT * FROM edges WHERE from_id = ? OR to_id = ?')\n .all(nodeId, nodeId) as EdgeRow[];\n }\n\n return rows.map((row) => this.mapEdgeRow(row));\n }\n\n listEdges(): Edge[] {\n const rows = this.db.prepare('SELECT * FROM edges').all() as EdgeRow[];\n return rows.map((row) => this.mapEdgeRow(row));\n }\n\n deleteEdge(id: string): void {\n this.db.prepare('DELETE FROM edges WHERE id = ?').run(id);\n }\n\n close(): void {\n this.db.close();\n }\n\n private ensureDirectory(): void {\n fs.mkdirSync(path.dirname(this.dbFilePath), { recursive: true });\n }\n\n private configure(): void {\n this.db.pragma('journal_mode = WAL');\n this.db.pragma('busy_timeout = 5000');\n this.db.pragma('synchronous = NORMAL');\n }\n\n private prepareSchema(): void {\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n type TEXT NOT NULL,\n data TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n from_id TEXT NOT NULL,\n to_id TEXT NOT NULL,\n type TEXT NOT NULL,\n weight REAL NOT NULL DEFAULT 1,\n metadata TEXT DEFAULT '{}',\n created_at TEXT NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_nodes_type ON nodes(type);\n CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_id);\n CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_id);\n CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(type);\n `);\n }\n\n private mapNodeRow(row: NodeRow): Node {\n return {\n id: row.id,\n type: row.type,\n data: JSON.parse(row.data),\n created_at: row.created_at,\n updated_at: row.updated_at\n } as Node;\n }\n\n private mapEdgeRow(row: EdgeRow): Edge {\n return {\n id: row.id,\n from_id: row.from_id,\n to_id: row.to_id,\n type: row.type,\n weight: row.weight,\n created_at: row.created_at,\n metadata: row.metadata ? (JSON.parse(row.metadata) as Record<string, unknown>) : {}\n };\n }\n}\n"],"mappings":"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","names":["path","fs","path","path","fs","path"]}
|
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getGuardianState
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-CFE7FZU7.js";
|
|
4
4
|
import {
|
|
5
5
|
BackupManager,
|
|
6
6
|
atomicWriteJSON,
|
|
7
7
|
getMemoryStats,
|
|
8
8
|
safeParseAndValidate,
|
|
9
9
|
searchIssues
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-JG2TAVAO.js";
|
|
11
|
+
import {
|
|
12
|
+
getTrieDirectory
|
|
13
|
+
} from "./chunk-D5VEUZLP.js";
|
|
11
14
|
|
|
12
15
|
// src/guardian/insight-store.ts
|
|
13
16
|
import { mkdir, readFile } from "fs/promises";
|
|
@@ -89,7 +92,7 @@ var InsightStore = class _InsightStore {
|
|
|
89
92
|
* Get the storage file path
|
|
90
93
|
*/
|
|
91
94
|
getStorePath() {
|
|
92
|
-
return join(this.projectPath, "
|
|
95
|
+
return join(getTrieDirectory(this.projectPath), "memory", "guardian-insights.json");
|
|
93
96
|
}
|
|
94
97
|
/**
|
|
95
98
|
* Create empty data structure
|
|
@@ -183,7 +186,7 @@ var InsightStore = class _InsightStore {
|
|
|
183
186
|
return;
|
|
184
187
|
}
|
|
185
188
|
const storePath = this.getStorePath();
|
|
186
|
-
const memoryDir = join(this.projectPath, "
|
|
189
|
+
const memoryDir = join(getTrieDirectory(this.projectPath), "memory");
|
|
187
190
|
await mkdir(memoryDir, { recursive: true });
|
|
188
191
|
const backupManager = new BackupManager(storePath);
|
|
189
192
|
await backupManager.createBackup();
|
|
@@ -1039,4 +1042,4 @@ export {
|
|
|
1039
1042
|
getGoalManager,
|
|
1040
1043
|
clearGoalManagers
|
|
1041
1044
|
};
|
|
1042
|
-
//# sourceMappingURL=chunk-
|
|
1045
|
+
//# sourceMappingURL=chunk-PFWGEHIA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/guardian/insight-store.ts","../src/guardian/goal-manager.ts"],"sourcesContent":["/**\n * Insight Store - Persistent storage for Guardian insights\n * \n * Phase 1 of Guardian Agency Plan: Fix critical persistence gaps\n * \n * Persists to: .trie/memory/guardian-insights.json\n * \n * Features:\n * - Insight persistence across restarts\n * - Cooldown state persistence (prevents duplicate insights)\n * - Dismissed insight tracking\n * - Atomic writes with backup rotation\n * - Zod validation for data integrity\n */\n\nimport { mkdir, readFile } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getTrieDirectory } from '../utils/workspace.js';\nimport { z } from 'zod';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { BackupManager } from '../utils/backup-manager.js';\nimport { safeParseAndValidate } from '../memory/validation.js';\n\n// ============================================================================\n// Schemas\n// ============================================================================\n\n/**\n * Schema for insight details\n */\nexport const InsightDetailsSchema = z.object({\n affectedFiles: z.array(z.string()).optional(),\n issueBreakdown: z.record(z.string(), z.number()).optional(),\n examples: z.array(z.string()).optional(),\n trend: z.enum(['improving', 'stable', 'worsening']).optional(),\n comparison: z.string().optional(),\n resolvedCount: z.number().optional(),\n resolvedIssues: z.array(z.object({\n file: z.string(),\n line: z.number().optional(),\n issue: z.string(),\n agent: z.string(),\n resolvedAt: z.string().optional(),\n })).optional(),\n summary: z.string().optional(),\n});\n\n/**\n * Schema for a Guardian insight\n */\nexport const GuardianInsightSchema = z.object({\n id: z.string(),\n type: z.enum(['observation', 'warning', 'suggestion', 'celebration', 'question']),\n message: z.string(),\n context: z.string().optional(),\n suggestedAction: z.string().optional(),\n actionCommand: z.string().optional(),\n relatedIssues: z.array(z.string()),\n priority: z.number().min(1).max(10),\n timestamp: z.number(),\n dismissed: z.boolean(),\n category: z.enum(['security', 'quality', 'performance', 'pattern', 'progress', 'general']),\n details: InsightDetailsSchema.optional(),\n});\n\nexport type GuardianInsight = z.infer<typeof GuardianInsightSchema>;\n\n/**\n * Schema for the entire insight store file\n */\nexport const InsightStoreDataSchema = z.object({\n version: z.literal(1),\n insights: z.array(GuardianInsightSchema),\n cooldowns: z.record(z.string(), z.number()), // insightKey -> timestamp\n dismissedIds: z.array(z.string()), // Track dismissed insight IDs permanently\n lastUpdated: z.string(),\n});\n\nexport type InsightStoreData = z.infer<typeof InsightStoreDataSchema>;\n\n// ============================================================================\n// InsightStore Class\n// ============================================================================\n\n/**\n * Persistent store for Guardian insights\n * \n * Usage:\n * ```typescript\n * const store = new InsightStore(projectPath);\n * await store.load();\n * \n * await store.addInsight(insight);\n * const active = store.getActiveInsights();\n * await store.dismissInsight(insightId);\n * ```\n */\nexport class InsightStore {\n private projectPath: string;\n private data: InsightStoreData;\n private loaded: boolean = false;\n private dirty: boolean = false;\n \n // Default cooldown periods (in ms)\n static readonly COOLDOWNS: Record<string, number> = {\n 'pre-push-warning': 60000, // 1 min between pre-push warnings\n 'security-warning': 30000, // 30s between security warnings\n 'new-issues': 30000, // 30s between new issue observations\n 'celebration': 60000, // 1 min between celebrations\n 'pattern-suggestion': 120000, // 2 min between pattern suggestions\n 'accessibility-visual-qa': 300000, // 5 min between visual QA suggestions\n 'goal-suggestion': 300000, // 5 min between goal suggestions\n 'risk-prediction': 180000, // 3 min between risk predictions\n 'hypothesis-update': 600000, // 10 min between hypothesis updates\n 'auto-escalation': 300000, // 5 min between auto-escalations\n };\n \n constructor(projectPath: string) {\n this.projectPath = projectPath;\n this.data = this.createEmptyData();\n }\n \n /**\n * Get the storage file path\n */\n private getStorePath(): string {\n return join(getTrieDirectory(this.projectPath), 'memory', 'guardian-insights.json');\n }\n \n /**\n * Create empty data structure\n */\n private createEmptyData(): InsightStoreData {\n return {\n version: 1,\n insights: [],\n cooldowns: {},\n dismissedIds: [],\n lastUpdated: new Date().toISOString(),\n };\n }\n \n /**\n * Load insights from disk\n * \n * If the file is corrupted, attempts recovery from backup.\n * Returns empty data if no valid file/backup exists.\n */\n async load(): Promise<InsightStoreData> {\n if (this.loaded) {\n return this.data;\n }\n \n const storePath = this.getStorePath();\n \n try {\n if (existsSync(storePath)) {\n const content = await readFile(storePath, 'utf-8');\n const result = safeParseAndValidate(content, InsightStoreDataSchema);\n \n if (result.success) {\n this.data = result.data;\n this.loaded = true;\n // Deduplicate any existing duplicate insights\n this.deduplicateInsights();\n return this.data;\n }\n \n // Validation failed - attempt recovery from backup\n console.error(` Insight store corrupted: ${result.error}`);\n const backupManager = new BackupManager(storePath);\n \n if (await backupManager.recoverFromBackup()) {\n console.error(' Recovered from backup');\n const recovered = await readFile(storePath, 'utf-8');\n const recoveredResult = safeParseAndValidate(recovered, InsightStoreDataSchema);\n if (recoveredResult.success) {\n this.data = recoveredResult.data;\n this.loaded = true;\n // Deduplicate any existing duplicate insights\n this.deduplicateInsights();\n return this.data;\n }\n }\n \n console.error(' No valid backup found, starting fresh');\n }\n } catch (error) {\n // File doesn't exist or recovery failed - start fresh\n console.error(` Could not load insight store: ${error}`);\n }\n \n this.data = this.createEmptyData();\n this.loaded = true;\n return this.data;\n }\n \n /**\n * Deduplicate existing insights on load\n * Keeps the most recent instance of each unique insight\n */\n private deduplicateInsights(): void {\n const seen = new Map<string, number>(); // contentKey -> index of first occurrence\n const toRemove: number[] = [];\n \n // Process from newest to oldest (insights are sorted by recency)\n for (let i = 0; i < this.data.insights.length; i++) {\n const insight = this.data.insights[i];\n if (!insight) continue;\n \n const contentKey = this.getContentKey(insight);\n \n if (seen.has(contentKey)) {\n // This is a duplicate - mark for removal\n toRemove.push(i);\n } else {\n seen.set(contentKey, i);\n }\n }\n \n // Remove duplicates (reverse order to preserve indices)\n if (toRemove.length > 0) {\n for (let i = toRemove.length - 1; i >= 0; i--) {\n const idx = toRemove[i];\n if (idx !== undefined) {\n this.data.insights.splice(idx, 1);\n }\n }\n this.dirty = true;\n }\n }\n \n /**\n * Save insights to disk\n * \n * Creates backup before writing, uses atomic write.\n */\n async save(): Promise<void> {\n if (!this.dirty && this.loaded) {\n return; // No changes to save\n }\n \n const storePath = this.getStorePath();\n const memoryDir = join(getTrieDirectory(this.projectPath), 'memory');\n \n // Ensure directory exists\n await mkdir(memoryDir, { recursive: true });\n \n // Create backup before writing\n const backupManager = new BackupManager(storePath);\n await backupManager.createBackup();\n \n // Update timestamp\n this.data.lastUpdated = new Date().toISOString();\n \n // Atomic write\n await atomicWriteJSON(storePath, this.data);\n \n this.dirty = false;\n }\n \n /**\n * Generate a content-based key for deduplication\n * Insights with the same content key are considered duplicates\n */\n private getContentKey(insight: GuardianInsight): string {\n // Normalize the message by removing specific numbers/counts that might vary slightly\n // e.g., \"Found 30 security issues\" and \"Found 31 security issues\" are the same insight\n const normalizedMessage = insight.message\n .replace(/\\d+/g, 'N') // Replace all numbers with N\n .toLowerCase()\n .trim();\n \n return `${insight.type}:${insight.category}:${normalizedMessage}`;\n }\n \n /**\n * Add an insight to the store\n * \n * Checks for duplicates using both insight ID and content similarity.\n * If a similar insight already exists (same type, category, and normalized message),\n * updates its timestamp instead of creating a duplicate.\n * Respects cooldowns to prevent insight spam.\n */\n async addInsight(insight: GuardianInsight): Promise<boolean> {\n await this.load();\n \n // Check if already exists by ID\n if (this.data.insights.some(i => i.id === insight.id)) {\n return false;\n }\n \n // Check if ID was previously dismissed (don't re-add)\n if (this.data.dismissedIds.includes(insight.id)) {\n return false;\n }\n \n // Check for content-based duplicates (same type, category, similar message)\n const contentKey = this.getContentKey(insight);\n const existingIndex = this.data.insights.findIndex(i => \n !i.dismissed && this.getContentKey(i) === contentKey\n );\n \n if (existingIndex >= 0) {\n // Update existing insight instead of adding duplicate\n const existing = this.data.insights[existingIndex];\n if (existing) {\n // Update with new data but keep the original ID\n existing.timestamp = insight.timestamp;\n existing.message = insight.message; // Update with current counts\n existing.details = insight.details; // Update details\n existing.relatedIssues = insight.relatedIssues;\n existing.suggestedAction = insight.suggestedAction;\n \n // Move to front of list\n this.data.insights.splice(existingIndex, 1);\n this.data.insights.unshift(existing);\n \n this.dirty = true;\n await this.save();\n }\n return false; // Return false to indicate no new insight was created\n }\n \n // Add to front of list\n this.data.insights.unshift(insight);\n \n // Keep only last 100 insights\n if (this.data.insights.length > 100) {\n this.data.insights = this.data.insights.slice(0, 100);\n }\n \n this.dirty = true;\n await this.save();\n \n return true;\n }\n \n /**\n * Check if a cooldown has expired for an insight type\n */\n canCreateInsight(insightKey: string): boolean {\n const lastTime = this.data.cooldowns[insightKey];\n const cooldown = InsightStore.COOLDOWNS[insightKey] || 30000;\n \n if (!lastTime) return true;\n return Date.now() - lastTime > cooldown;\n }\n \n /**\n * Mark that an insight type was created (set cooldown)\n */\n async markInsightCreated(insightKey: string): Promise<void> {\n await this.load();\n this.data.cooldowns[insightKey] = Date.now();\n this.dirty = true;\n await this.save();\n }\n \n /**\n * Get active (non-dismissed) insights\n * \n * Returns insights sorted by priority (highest first),\n * limited to the specified count.\n */\n getActiveInsights(limit: number = 5): GuardianInsight[] {\n return this.data.insights\n .filter(i => !i.dismissed)\n .sort((a, b) => b.priority - a.priority)\n .slice(0, limit);\n }\n \n /**\n * Get all insights (including dismissed)\n */\n getAllInsights(): GuardianInsight[] {\n return [...this.data.insights];\n }\n \n /**\n * Dismiss an insight by ID\n */\n async dismissInsight(insightId: string): Promise<boolean> {\n await this.load();\n \n const insight = this.data.insights.find(i => i.id === insightId);\n if (!insight) {\n return false;\n }\n \n insight.dismissed = true;\n \n // Track permanently dismissed IDs\n if (!this.data.dismissedIds.includes(insightId)) {\n this.data.dismissedIds.push(insightId);\n \n // Keep only last 500 dismissed IDs\n if (this.data.dismissedIds.length > 500) {\n this.data.dismissedIds = this.data.dismissedIds.slice(-500);\n }\n }\n \n this.dirty = true;\n await this.save();\n \n return true;\n }\n \n /**\n * Remove an insight entirely\n */\n async removeInsight(insightId: string): Promise<boolean> {\n await this.load();\n \n const index = this.data.insights.findIndex(i => i.id === insightId);\n if (index === -1) {\n return false;\n }\n \n this.data.insights.splice(index, 1);\n this.dirty = true;\n await this.save();\n \n return true;\n }\n \n /**\n * Clear all cooldowns\n */\n async clearCooldowns(): Promise<void> {\n await this.load();\n this.data.cooldowns = {};\n this.dirty = true;\n await this.save();\n }\n \n /**\n * Get insight by ID\n */\n getInsight(insightId: string): GuardianInsight | undefined {\n return this.data.insights.find(i => i.id === insightId);\n }\n \n /**\n * Update an existing insight\n */\n async updateInsight(insightId: string, updates: Partial<GuardianInsight>): Promise<boolean> {\n await this.load();\n \n const insight = this.data.insights.find(i => i.id === insightId);\n if (!insight) {\n return false;\n }\n \n Object.assign(insight, updates);\n this.dirty = true;\n await this.save();\n \n return true;\n }\n \n /**\n * Get insights by category\n */\n getInsightsByCategory(category: GuardianInsight['category']): GuardianInsight[] {\n return this.data.insights.filter(i => i.category === category && !i.dismissed);\n }\n \n /**\n * Get insights by type\n */\n getInsightsByType(type: GuardianInsight['type']): GuardianInsight[] {\n return this.data.insights.filter(i => i.type === type && !i.dismissed);\n }\n \n /**\n * Get insights from the last N hours\n */\n getRecentInsights(hours: number = 24): GuardianInsight[] {\n const cutoff = Date.now() - (hours * 60 * 60 * 1000);\n return this.data.insights.filter(i => i.timestamp >= cutoff);\n }\n \n /**\n * Get statistics about insights\n */\n getStats(): {\n total: number;\n active: number;\n dismissed: number;\n byCategory: Record<string, number>;\n byType: Record<string, number>;\n } {\n const stats = {\n total: this.data.insights.length,\n active: 0,\n dismissed: 0,\n byCategory: {} as Record<string, number>,\n byType: {} as Record<string, number>,\n };\n \n for (const insight of this.data.insights) {\n if (insight.dismissed) {\n stats.dismissed++;\n } else {\n stats.active++;\n }\n \n stats.byCategory[insight.category] = (stats.byCategory[insight.category] || 0) + 1;\n stats.byType[insight.type] = (stats.byType[insight.type] || 0) + 1;\n }\n \n return stats;\n }\n \n /**\n * Prune old insights (older than N days)\n */\n async pruneOldInsights(daysToKeep: number = 30): Promise<number> {\n await this.load();\n \n const cutoff = Date.now() - (daysToKeep * 24 * 60 * 60 * 1000);\n const originalCount = this.data.insights.length;\n \n this.data.insights = this.data.insights.filter(i => i.timestamp >= cutoff);\n \n const pruned = originalCount - this.data.insights.length;\n if (pruned > 0) {\n this.dirty = true;\n await this.save();\n }\n \n return pruned;\n }\n \n /**\n * Check if the store has been loaded\n */\n isLoaded(): boolean {\n return this.loaded;\n }\n \n /**\n * Force reload from disk\n */\n async reload(): Promise<InsightStoreData> {\n this.loaded = false;\n this.dirty = false;\n return this.load();\n }\n}\n\n// ============================================================================\n// Singleton Management\n// ============================================================================\n\nconst insightStores: Map<string, InsightStore> = new Map();\n\n/**\n * Get the InsightStore for a project (singleton per project)\n */\nexport function getInsightStore(projectPath: string): InsightStore {\n let store = insightStores.get(projectPath);\n if (!store) {\n store = new InsightStore(projectPath);\n insightStores.set(projectPath, store);\n }\n return store;\n}\n\n/**\n * Clear all InsightStore instances (for testing)\n */\nexport function clearInsightStores(): void {\n insightStores.clear();\n}\n","/**\n * Goal Manager - Autonomous goal generation and tracking\n * \n * Phase 2 of Guardian Agency Plan: Autonomous Goals\n * \n * Features:\n * - Auto-generates goals from incident patterns\n * - Tracks goal progress over time\n * - Presents goals to users for acceptance/rejection\n * - Adaptive goal difficulty based on team velocity\n * - Goal achievement celebrations\n */\n\nimport type { Goal } from './guardian-state.js';\nimport { getGuardianState } from './guardian-state.js';\nimport { getInsightStore, type GuardianInsight } from './insight-store.js';\nimport { searchIssues, getMemoryStats } from '../memory/issue-store.js';\nimport { basename } from 'path';\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * A pattern detected from incident history\n */\nexport interface IncidentPattern {\n type: 'file-cluster' | 'severity-trend' | 'agent-concentration' | 'time-pattern';\n description: string;\n metric: string;\n currentValue: number;\n suggestedTarget: number;\n confidence: number; // 0-1\n evidence: string[];\n category?: 'security' | 'quality' | 'performance' | 'coverage' | 'general';\n}\n\n/**\n * Goal opportunity - a potential goal before user acceptance\n */\nexport interface GoalOpportunity {\n pattern: IncidentPattern;\n goal: Omit<Goal, 'id' | 'createdAt' | 'updatedAt'>;\n reasoning: string;\n}\n\n/**\n * Configuration for goal generation\n */\nexport interface GoalGenerationConfig {\n minConfidence: number; // Minimum confidence to suggest goal (0-1)\n maxActiveGoals: number; // Maximum concurrent active goals\n goalDurationDays: number; // Default goal duration in days\n reductionTargetPercent: number; // Target reduction percentage\n}\n\nconst DEFAULT_CONFIG: GoalGenerationConfig = {\n minConfidence: 0.6,\n maxActiveGoals: 3,\n goalDurationDays: 14,\n reductionTargetPercent: 50,\n};\n\n// ============================================================================\n// GoalManager Class\n// ============================================================================\n\n/**\n * Manages autonomous goal generation and tracking\n */\nexport class GoalManager {\n private projectPath: string;\n private config: GoalGenerationConfig;\n private guardianState;\n private insightStore;\n \n constructor(projectPath: string, config: Partial<GoalGenerationConfig> = {}) {\n this.projectPath = projectPath;\n this.config = { ...DEFAULT_CONFIG, ...config };\n this.guardianState = getGuardianState(projectPath);\n this.insightStore = getInsightStore(projectPath);\n }\n \n /**\n * Analyze incident patterns from memory\n */\n async analyzeIncidentPatterns(): Promise<IncidentPattern[]> {\n const patterns: IncidentPattern[] = [];\n \n try {\n // Get recent issues for analysis\n const stats = await getMemoryStats(this.projectPath);\n const recentIssues = await searchIssues('', {\n workDir: this.projectPath,\n limit: 500,\n includeResolved: true,\n });\n \n if (recentIssues.length < 5) {\n return patterns; // Not enough data for pattern detection\n }\n \n // 1. Analyze file clusters (files with most issues)\n const fileIssueCount = new Map<string, number>();\n for (const { issue } of recentIssues) {\n const file = issue.file;\n fileIssueCount.set(file, (fileIssueCount.get(file) || 0) + 1);\n }\n \n const sortedFiles = [...fileIssueCount.entries()]\n .sort((a, b) => b[1] - a[1]);\n \n // Detect hot directories\n const dirIssueCount = new Map<string, number>();\n for (const [file, count] of sortedFiles) {\n const parts = file.split('/');\n if (parts.length > 1) {\n const dir = parts.slice(0, -1).join('/');\n dirIssueCount.set(dir, (dirIssueCount.get(dir) || 0) + count);\n }\n }\n \n const sortedDirs = [...dirIssueCount.entries()]\n .sort((a, b) => b[1] - a[1]);\n \n if (sortedDirs.length > 0) {\n const [topDir, topDirCount] = sortedDirs[0]!;\n const totalIssues = recentIssues.length;\n const percentage = (topDirCount / totalIssues) * 100;\n \n if (percentage >= 30) {\n patterns.push({\n type: 'file-cluster',\n description: `${basename(topDir)}/ has ${percentage.toFixed(0)}% of issues`,\n metric: `${topDir}_issues`,\n currentValue: topDirCount,\n suggestedTarget: Math.floor(topDirCount * (1 - this.config.reductionTargetPercent / 100)),\n confidence: Math.min(0.9, percentage / 100 + 0.3),\n evidence: [\n `${topDirCount} issues in ${topDir}/`,\n `${percentage.toFixed(0)}% of total issues`,\n `Top files: ${sortedFiles.filter(([f]) => f.startsWith(topDir)).slice(0, 3).map(([f]) => basename(f)).join(', ')}`,\n ],\n category: 'quality',\n });\n }\n }\n \n // 2. Analyze severity trends\n const criticalCount = recentIssues.filter(r => r.issue.severity === 'critical').length;\n const seriousCount = recentIssues.filter(r => r.issue.severity === 'serious').length;\n \n if (criticalCount >= 3) {\n patterns.push({\n type: 'severity-trend',\n description: `${criticalCount} critical issues need attention`,\n metric: 'critical_issues',\n currentValue: criticalCount,\n suggestedTarget: 0,\n confidence: Math.min(0.95, 0.5 + criticalCount * 0.1),\n evidence: [\n `${criticalCount} critical severity issues`,\n `${seriousCount} serious severity issues`,\n 'Critical issues should be zero for production safety',\n ],\n category: 'security',\n });\n }\n \n // 3. Analyze agent concentration (skill-specific issues)\n const agentIssueCount = new Map<string, number>();\n for (const { issue } of recentIssues) {\n agentIssueCount.set(issue.agent, (agentIssueCount.get(issue.agent) || 0) + 1);\n }\n \n const sortedAgents = [...agentIssueCount.entries()]\n .sort((a, b) => b[1] - a[1]);\n \n if (sortedAgents.length > 0) {\n const [topAgent, topAgentCount] = sortedAgents[0]!;\n const percentage = (topAgentCount / recentIssues.length) * 100;\n \n if (percentage >= 40 && topAgentCount >= 5) {\n const category = this.agentToCategory(topAgent);\n patterns.push({\n type: 'agent-concentration',\n description: `${topAgent} skill finds ${percentage.toFixed(0)}% of issues`,\n metric: `${topAgent}_issues`,\n currentValue: topAgentCount,\n suggestedTarget: Math.floor(topAgentCount * 0.5),\n confidence: Math.min(0.85, percentage / 100 + 0.2),\n evidence: [\n `${topAgentCount} issues from ${topAgent}`,\n `${percentage.toFixed(0)}% of all issues`,\n `Suggests focused improvement in ${category} area`,\n ],\n category,\n });\n }\n }\n \n // 4. Detect improvement trends (for streak goals)\n if (stats.improvementTrend === 'improving') {\n patterns.push({\n type: 'time-pattern',\n description: 'Quality is improving - maintain the streak',\n metric: 'clean_scans',\n currentValue: 0,\n suggestedTarget: 5,\n confidence: 0.7,\n evidence: [\n 'Historical trend shows improvement',\n 'Momentum is positive',\n 'Streak goal can maintain motivation',\n ],\n category: 'quality',\n });\n }\n \n } catch (error) {\n console.error('Failed to analyze incident patterns:', error);\n }\n \n return patterns;\n }\n \n /**\n * Convert agent name to category\n */\n private agentToCategory(agent: string): 'security' | 'quality' | 'performance' | 'coverage' | 'general' {\n const categoryMap: Record<string, 'security' | 'quality' | 'performance' | 'coverage' | 'general'> = {\n 'security': 'security',\n 'privacy': 'security',\n 'soc2': 'security',\n 'performance': 'performance',\n 'accessibility': 'quality',\n 'test': 'coverage',\n 'typecheck': 'quality',\n 'bug-finding': 'quality',\n };\n return categoryMap[agent] || 'general';\n }\n \n /**\n * Generate goal opportunities from patterns\n */\n async generateGoalOpportunities(): Promise<GoalOpportunity[]> {\n const patterns = await this.analyzeIncidentPatterns();\n const opportunities: GoalOpportunity[] = [];\n \n // Filter by confidence threshold\n const validPatterns = patterns.filter(p => p.confidence >= this.config.minConfidence);\n \n // Check current active goals\n await this.guardianState.load();\n const activeGoals = this.guardianState.getActiveGoals();\n \n // Don't suggest too many goals\n const slotsAvailable = this.config.maxActiveGoals - activeGoals.length;\n if (slotsAvailable <= 0) {\n return opportunities;\n }\n \n // Convert patterns to goal opportunities\n for (const pattern of validPatterns.slice(0, slotsAvailable)) {\n const goalType = pattern.type === 'time-pattern' ? 'streak' : 'reduction';\n const deadline = new Date();\n deadline.setDate(deadline.getDate() + this.config.goalDurationDays);\n \n opportunities.push({\n pattern,\n goal: {\n description: this.generateGoalDescription(pattern),\n type: goalType,\n metric: pattern.metric,\n target: pattern.suggestedTarget,\n currentValue: pattern.currentValue,\n startValue: pattern.currentValue,\n status: 'active',\n autoGenerated: true,\n confidence: pattern.confidence,\n deadline: deadline.toISOString(),\n category: pattern.category,\n evidence: pattern.evidence,\n },\n reasoning: this.generateGoalReasoning(pattern),\n });\n }\n \n return opportunities;\n }\n \n /**\n * Generate a human-readable goal description\n */\n private generateGoalDescription(pattern: IncidentPattern): string {\n switch (pattern.type) {\n case 'file-cluster':\n return `Reduce issues in ${pattern.description.split(' ')[0]} by ${this.config.reductionTargetPercent}%`;\n case 'severity-trend':\n return 'Eliminate all critical issues';\n case 'agent-concentration':\n return `Reduce ${pattern.description.split(' ')[0]} issues by 50%`;\n case 'time-pattern':\n return 'Achieve 5 consecutive clean scans';\n default:\n return pattern.description;\n }\n }\n \n /**\n * Generate reasoning for why this goal was suggested\n */\n private generateGoalReasoning(pattern: IncidentPattern): string {\n const evidence = pattern.evidence.join('. ');\n return `Based on analysis: ${evidence}. Confidence: ${(pattern.confidence * 100).toFixed(0)}%`;\n }\n \n /**\n * Auto-generate goals and create them (with auto-generated status)\n * \n * Returns goals that need user acceptance.\n */\n async autoGenerateGoals(): Promise<Goal[]> {\n const opportunities = await this.generateGoalOpportunities();\n const createdGoals: Goal[] = [];\n \n for (const opportunity of opportunities) {\n const goal: Goal = {\n id: `goal-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,\n ...opportunity.goal,\n createdAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n };\n \n await this.guardianState.addGoal(goal);\n createdGoals.push(goal);\n \n // Create insight about the new goal\n if (this.insightStore.canCreateInsight('goal-suggestion')) {\n const insight: GuardianInsight = {\n id: `insight-goal-${goal.id}`,\n type: 'suggestion',\n message: `New goal suggested: ${goal.description}`,\n context: opportunity.reasoning,\n suggestedAction: 'Review and accept/reject this goal',\n relatedIssues: [],\n priority: 6,\n timestamp: Date.now(),\n dismissed: false,\n category: 'progress',\n details: {\n examples: opportunity.pattern.evidence,\n },\n };\n await this.insightStore.addInsight(insight);\n await this.insightStore.markInsightCreated('goal-suggestion');\n }\n }\n \n return createdGoals;\n }\n \n /**\n * Update goal progress based on current state\n */\n async updateGoalProgress(): Promise<void> {\n await this.guardianState.load();\n const activeGoals = this.guardianState.getActiveGoals();\n \n for (const goal of activeGoals) {\n const currentValue = await this.measureGoalMetric(goal);\n \n // Update current value\n await this.guardianState.updateGoal(goal.id, { currentValue });\n \n // Check if goal achieved\n if (this.isGoalAchieved(goal, currentValue)) {\n await this.guardianState.updateGoal(goal.id, {\n status: 'achieved',\n achievedAt: new Date().toISOString(),\n currentValue,\n });\n \n // Celebrate!\n await this.celebrateGoalAchievement(goal);\n }\n \n // Check if goal failed (past deadline and not achieved)\n if (goal.deadline) {\n const deadline = new Date(goal.deadline);\n if (Date.now() > deadline.getTime() && !this.isGoalAchieved(goal, currentValue)) {\n await this.guardianState.updateGoal(goal.id, {\n status: 'failed',\n currentValue,\n });\n }\n }\n }\n }\n \n /**\n * Measure the current value of a goal's metric\n * \n * Supports both structured metrics and semantic/natural language goals\n */\n private async measureGoalMetric(goal: Goal): Promise<number> {\n try {\n const issues = await searchIssues('', {\n workDir: this.projectPath,\n limit: 1000,\n includeResolved: false,\n });\n \n // Structured metrics (auto-generated goals)\n if (goal.metric.endsWith('_issues')) {\n const prefix = goal.metric.replace('_issues', '');\n \n // Check if it's a directory metric\n if (prefix.includes('/')) {\n return issues.filter(r => r.issue.file.startsWith(prefix)).length;\n }\n \n // Check if it's an agent metric\n return issues.filter(r => r.issue.agent === prefix).length;\n }\n \n if (goal.metric === 'critical_issues') {\n return issues.filter(r => r.issue.severity === 'critical').length;\n }\n \n // Semantic goal tracking - match description to issue types\n const desc = goal.description.toLowerCase();\n \n // Path-aware matching for directory/module-specific goals\n // Matches patterns like \"in the auth module\", \"in src/\", \"in components folder\"\n const dirMatch = goal.description.match(/in\\s+(?:the\\s+)?(\\S+?)(?:\\s+(?:module|folder|directory|dir))?(?:\\s|$)/i);\n if (dirMatch && dirMatch[1]) {\n const dirName = dirMatch[1].toLowerCase().replace(/[/\\\\]$/, ''); // Normalize trailing slashes\n const matchingIssues = issues.filter(r => {\n const filePath = r.issue.file.toLowerCase();\n // Match directory name anywhere in path (e.g., \"auth\" matches \"src/auth/login.ts\")\n return filePath.includes(`/${dirName}/`) || \n filePath.includes(`\\\\${dirName}\\\\`) ||\n filePath.startsWith(`${dirName}/`) ||\n filePath.startsWith(`${dirName}\\\\`);\n });\n if (matchingIssues.length > 0 || desc.includes(dirName)) {\n return matchingIssues.length;\n }\n }\n \n // Dead code / unused code goals\n if (desc.includes('dead code') || desc.includes('unused') || desc.includes('remove unused')) {\n const deadCodeIssues = issues.filter(r => {\n const msg = r.issue.issue.toLowerCase();\n return msg.includes('unused') || msg.includes('dead code') || \n msg.includes('never used') || msg.includes('unreachable') ||\n msg.includes('no-unused') || msg.includes('defined but never');\n });\n return deadCodeIssues.length;\n }\n \n // Security goals\n if (desc.includes('security') || desc.includes('vulnerab') || desc.includes('fix security')) {\n const securityIssues = issues.filter(r => \n r.issue.agent === 'security' || r.issue.agent === 'privacy' ||\n r.issue.severity === 'critical'\n );\n return securityIssues.length;\n }\n \n // Type safety goals\n if (desc.includes('type') || desc.includes('typescript') || desc.includes('any type')) {\n const typeIssues = issues.filter(r => \n r.issue.agent === 'typecheck' ||\n r.issue.issue.toLowerCase().includes('type') ||\n r.issue.issue.toLowerCase().includes('any')\n );\n return typeIssues.length;\n }\n \n // Test coverage goals\n if (desc.includes('test') || desc.includes('coverage')) {\n const testIssues = issues.filter(r => \n r.issue.agent === 'test' ||\n r.issue.issue.toLowerCase().includes('test') ||\n r.issue.issue.toLowerCase().includes('coverage')\n );\n return testIssues.length;\n }\n \n // Performance goals\n if (desc.includes('performance') || desc.includes('slow') || desc.includes('optimize')) {\n const perfIssues = issues.filter(r => \n r.issue.agent === 'performance' ||\n r.issue.issue.toLowerCase().includes('performance') ||\n r.issue.issue.toLowerCase().includes('slow')\n );\n return perfIssues.length;\n }\n \n // Accessibility goals\n if (desc.includes('accessibility') || desc.includes('a11y') || desc.includes('accessible')) {\n const a11yIssues = issues.filter(r => \n r.issue.agent === 'accessibility' ||\n r.issue.issue.toLowerCase().includes('accessibility')\n );\n return a11yIssues.length;\n }\n \n // Bug-related goals\n if (desc.includes('bug') || desc.includes('fix') || desc.includes('error')) {\n const bugIssues = issues.filter(r => \n r.issue.agent === 'bug-finding' ||\n r.issue.severity === 'critical' ||\n r.issue.severity === 'serious'\n );\n return bugIssues.length;\n }\n \n // Quality goals (general)\n if (desc.includes('quality') || desc.includes('clean') || desc.includes('improve')) {\n // Count all issues as baseline for quality\n return issues.length;\n }\n \n // Default: total issues\n return issues.length;\n } catch {\n return goal.currentValue; // Return existing value on error\n }\n }\n \n /**\n * Check if a goal has been achieved\n */\n private isGoalAchieved(goal: Goal, currentValue: number): boolean {\n switch (goal.type) {\n case 'reduction':\n return currentValue <= goal.target;\n case 'score':\n return currentValue >= goal.target;\n case 'streak':\n return currentValue >= goal.target;\n default:\n return currentValue <= goal.target;\n }\n }\n \n /**\n * Create a celebration insight for goal achievement\n */\n private async celebrateGoalAchievement(goal: Goal): Promise<void> {\n // Find resolved issues that match this goal's metric\n const resolvedDetails = await this.getResolvedIssuesForGoal(goal);\n \n // Validate required fields\n if (goal.startValue === undefined || goal.startValue === null) {\n throw new Error(`Goal ${goal.id} missing startValue`);\n }\n if (goal.currentValue === undefined || goal.currentValue === null) {\n throw new Error(`Goal ${goal.id} missing currentValue`);\n }\n if (goal.target === undefined || goal.target === null) {\n throw new Error(`Goal ${goal.id} missing target`);\n }\n \n // Validate resolvedDetails structure\n for (let i = 0; i < resolvedDetails.length; i++) {\n const issue = resolvedDetails[i];\n if (!issue) {\n throw new Error(`Resolved issue at index ${i} is null/undefined`);\n }\n if (!issue.file) {\n throw new Error(`Resolved issue at index ${i} missing file field`);\n }\n if (!issue.issue) {\n throw new Error(`Resolved issue at index ${i} missing issue description`);\n }\n if (!issue.agent) {\n throw new Error(`Resolved issue at index ${i} missing agent field`);\n }\n }\n \n const insight: GuardianInsight = {\n id: `insight-achieved-${goal.id}`,\n type: 'celebration',\n message: `Goal achieved: ${goal.description}!`,\n context: `Started at ${goal.startValue}, now at ${goal.currentValue}. Target was ${goal.target}.`,\n relatedIssues: [],\n priority: 8,\n timestamp: Date.now(),\n dismissed: false,\n category: 'progress',\n details: {\n resolvedCount: resolvedDetails.length,\n resolvedIssues: resolvedDetails.slice(0, 20).map(issue => ({\n file: issue.file,\n line: issue.line,\n issue: issue.issue,\n agent: issue.agent,\n resolvedAt: issue.resolvedAt,\n })),\n summary: resolvedDetails.length > 0 \n ? `Resolved ${resolvedDetails.length} issue${resolvedDetails.length > 1 ? 's' : ''} matching this goal`\n : 'Progress tracked via metric reduction',\n },\n };\n \n // Validate insight structure before saving\n if (!insight.details) {\n throw new Error('Failed to create details object for goal achievement insight');\n }\n if (insight.details.resolvedCount === undefined) {\n throw new Error('resolvedCount is undefined in goal achievement insight');\n }\n if (insight.details.resolvedCount > 0 && (!insight.details.resolvedIssues || insight.details.resolvedIssues.length === 0)) {\n throw new Error(`resolvedCount is ${insight.details.resolvedCount} but resolvedIssues array is empty`);\n }\n if (insight.details.resolvedCount !== insight.details.resolvedIssues?.length) {\n throw new Error(`resolvedCount (${insight.details.resolvedCount}) doesn't match resolvedIssues length (${insight.details.resolvedIssues?.length})`);\n }\n \n await this.insightStore.addInsight(insight);\n }\n\n /**\n * Get resolved issues that match a goal's metric pattern\n */\n private async getResolvedIssuesForGoal(goal: Goal): Promise<Array<{ file: string; line: number | undefined; issue: string; agent: string; resolvedAt: string | undefined }>> {\n try {\n // Get all resolved issues\n const allResolved = await searchIssues('', {\n workDir: this.projectPath,\n limit: 1000,\n includeResolved: true,\n });\n \n // Filter to only resolved issues\n const resolved = allResolved\n .map(r => r.issue)\n .filter(issue => issue.resolved === true);\n \n // Filter by goal's metric pattern (same logic as measureGoalMetric)\n const desc = goal.description.toLowerCase();\n const metric = goal.metric.toLowerCase();\n \n let matchingResolved = resolved;\n \n // Match by metric pattern\n if (metric.endsWith('_issues')) {\n const prefix = metric.replace('_issues', '');\n if (prefix.includes('/')) {\n matchingResolved = resolved.filter(i => i.file.startsWith(prefix));\n } else {\n matchingResolved = resolved.filter(i => i.agent === prefix);\n }\n } else if (metric === 'critical_issues') {\n matchingResolved = resolved.filter(i => i.severity === 'critical');\n } else {\n // Semantic matching (same as measureGoalMetric)\n if (desc.includes('dead code') || desc.includes('unused') || desc.includes('remove unused')) {\n matchingResolved = resolved.filter(i => {\n const msg = i.issue.toLowerCase();\n return msg.includes('unused') || msg.includes('dead code') || \n msg.includes('never used') || msg.includes('unreachable') ||\n msg.includes('no-unused') || msg.includes('defined but never');\n });\n } else if (desc.includes('security') || desc.includes('vulnerab') || desc.includes('fix security')) {\n matchingResolved = resolved.filter(i => \n i.agent === 'security' || i.agent === 'privacy' || i.severity === 'critical'\n );\n } else if (desc.includes('type') || desc.includes('typescript') || desc.includes('any type')) {\n matchingResolved = resolved.filter(i => \n i.agent === 'typecheck' ||\n i.issue.toLowerCase().includes('type') ||\n i.issue.toLowerCase().includes('any')\n );\n } else if (desc.includes('test') || desc.includes('coverage')) {\n matchingResolved = resolved.filter(i => \n i.agent === 'test' ||\n i.issue.toLowerCase().includes('test') ||\n i.issue.toLowerCase().includes('coverage')\n );\n } else if (desc.includes('performance') || desc.includes('slow') || desc.includes('optimize')) {\n matchingResolved = resolved.filter(i => \n i.agent === 'performance' ||\n i.issue.toLowerCase().includes('performance') ||\n i.issue.toLowerCase().includes('slow')\n );\n } else if (desc.includes('accessibility') || desc.includes('a11y') || desc.includes('accessible')) {\n matchingResolved = resolved.filter(i => \n i.agent === 'accessibility' ||\n i.issue.toLowerCase().includes('accessibility')\n );\n } else if (desc.includes('bug') || desc.includes('fix') || desc.includes('error')) {\n matchingResolved = resolved.filter(i => \n i.agent === 'bug-finding' ||\n i.severity === 'critical' ||\n i.severity === 'serious'\n );\n }\n }\n \n // Filter by resolvedAt timestamp (only include issues resolved during goal's lifetime)\n const goalCreatedAt = new Date(goal.createdAt).getTime();\n const goalAchievedAt = goal.achievedAt ? new Date(goal.achievedAt).getTime() : Date.now();\n \n return matchingResolved\n .filter(issue => {\n if (!issue.resolvedAt) return false;\n const resolvedAt = new Date(issue.resolvedAt).getTime();\n return resolvedAt >= goalCreatedAt && resolvedAt <= goalAchievedAt;\n })\n .sort((a, b) => {\n // Sort by resolvedAt, most recent first\n const aTime = a.resolvedAt ? new Date(a.resolvedAt).getTime() : 0;\n const bTime = b.resolvedAt ? new Date(b.resolvedAt).getTime() : 0;\n return bTime - aTime;\n });\n } catch {\n return [];\n }\n }\n \n /**\n * Accept an auto-generated goal\n */\n async acceptGoal(goalId: string): Promise<boolean> {\n return this.guardianState.respondToGoal(goalId, true);\n }\n \n /**\n * Reject an auto-generated goal\n */\n async rejectGoal(goalId: string): Promise<boolean> {\n return this.guardianState.respondToGoal(goalId, false);\n }\n \n /**\n * Get pending auto-generated goals (awaiting acceptance)\n */\n getPendingGoals(): Goal[] {\n return this.guardianState.getAutoGeneratedGoals()\n .filter(g => g.status === 'active');\n }\n \n /**\n * Get goal progress summary\n */\n getGoalProgressSummary(): {\n active: number;\n achieved: number;\n failed: number;\n pending: number;\n } {\n const goals = this.guardianState.getAllGoals();\n return {\n active: goals.filter(g => g.status === 'active').length,\n achieved: goals.filter(g => g.status === 'achieved').length,\n failed: goals.filter(g => g.status === 'failed').length,\n pending: goals.filter(g => g.autoGenerated && g.status === 'active').length,\n };\n }\n}\n\n// ============================================================================\n// Adaptive Scan Frequency\n// ============================================================================\n\n/**\n * Calculate optimal scan frequency based on current risk level\n */\nexport async function calculateAdaptiveScanFrequency(projectPath: string): Promise<{\n frequencyMs: number;\n reason: string;\n}> {\n const guardianState = getGuardianState(projectPath);\n await guardianState.load();\n \n try {\n const stats = await getMemoryStats(projectPath);\n const issues = await searchIssues('', {\n workDir: projectPath,\n limit: 100,\n includeResolved: false,\n });\n \n const criticalCount = issues.filter(r => r.issue.severity === 'critical').length;\n const seriousCount = issues.filter(r => r.issue.severity === 'serious').length;\n \n // High risk: scan every minute\n if (criticalCount >= 3) {\n return {\n frequencyMs: 60000,\n reason: `${criticalCount} critical issues detected - scanning frequently`,\n };\n }\n \n // Medium-high risk: scan every 2 minutes\n if (criticalCount > 0 || seriousCount >= 5) {\n return {\n frequencyMs: 120000,\n reason: `Critical or many serious issues - elevated scan frequency`,\n };\n }\n \n // Medium risk: scan every 3 minutes\n if (seriousCount > 0) {\n return {\n frequencyMs: 180000,\n reason: `${seriousCount} serious issues - moderate scan frequency`,\n };\n }\n \n // Low risk: scan every 5 minutes (default)\n if (stats.totalIssues > 10) {\n return {\n frequencyMs: 300000,\n reason: 'Some issues present - standard scan frequency',\n };\n }\n \n // Very low risk: scan every 10 minutes\n return {\n frequencyMs: 600000,\n reason: 'Code looks good - relaxed scan frequency',\n };\n \n } catch {\n // Default on error\n return {\n frequencyMs: 300000,\n reason: 'Default scan frequency (5 min)',\n };\n }\n}\n\n/**\n * Apply adaptive scan frequency\n */\nexport async function adaptScanFrequency(projectPath: string): Promise<number> {\n const guardianState = getGuardianState(projectPath);\n const { frequencyMs } = await calculateAdaptiveScanFrequency(projectPath);\n \n await guardianState.setScanFrequency(frequencyMs);\n \n return frequencyMs;\n}\n\n// ============================================================================\n// Singleton Management\n// ============================================================================\n\nconst goalManagers: Map<string, GoalManager> = new Map();\n\n/**\n * Get the GoalManager for a project (singleton per project)\n */\nexport function getGoalManager(projectPath: string): GoalManager {\n let manager = goalManagers.get(projectPath);\n if (!manager) {\n manager = new GoalManager(projectPath);\n goalManagers.set(projectPath, manager);\n }\n return manager;\n}\n\n/**\n * Clear all GoalManager instances (for testing)\n */\nexport function clearGoalManagers(): void {\n goalManagers.clear();\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
|
+
getTrieDirectory,
|
|
2
3
|
getWorkingDirectory
|
|
3
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-D5VEUZLP.js";
|
|
4
5
|
|
|
5
6
|
// src/ingest/agent-builder.ts
|
|
6
7
|
import Anthropic2 from "@anthropic-ai/sdk";
|
|
@@ -913,7 +914,7 @@ function buildActivationRules(knowledge) {
|
|
|
913
914
|
};
|
|
914
915
|
}
|
|
915
916
|
async function saveAgentConfig(config) {
|
|
916
|
-
const trieDir = join(getWorkingDirectory(void 0, true), "
|
|
917
|
+
const trieDir = join(getTrieDirectory(getWorkingDirectory(void 0, true)), "agents");
|
|
917
918
|
await mkdir(trieDir, { recursive: true });
|
|
918
919
|
const configPath = join(trieDir, `${config.name}.json`);
|
|
919
920
|
await writeFile(configPath, JSON.stringify(config, null, 2));
|
|
@@ -921,7 +922,7 @@ async function saveAgentConfig(config) {
|
|
|
921
922
|
}
|
|
922
923
|
async function loadAgentConfig(name) {
|
|
923
924
|
try {
|
|
924
|
-
const configPath = join(getWorkingDirectory(void 0, true), "
|
|
925
|
+
const configPath = join(getTrieDirectory(getWorkingDirectory(void 0, true)), "agents", `${name}.json`);
|
|
925
926
|
const content = await readFile2(configPath, "utf-8");
|
|
926
927
|
return JSON.parse(content);
|
|
927
928
|
} catch {
|
|
@@ -931,7 +932,7 @@ async function loadAgentConfig(name) {
|
|
|
931
932
|
async function listCustomAgents() {
|
|
932
933
|
try {
|
|
933
934
|
const { readdir } = await import("fs/promises");
|
|
934
|
-
const trieDir = join(getWorkingDirectory(void 0, true), "
|
|
935
|
+
const trieDir = join(getTrieDirectory(getWorkingDirectory(void 0, true)), "agents");
|
|
935
936
|
const files = await readdir(trieDir);
|
|
936
937
|
return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(".json", ""));
|
|
937
938
|
} catch {
|
|
@@ -951,4 +952,4 @@ export {
|
|
|
951
952
|
loadAgentConfig,
|
|
952
953
|
listCustomAgents
|
|
953
954
|
};
|
|
954
|
-
//# sourceMappingURL=chunk-
|
|
955
|
+
//# sourceMappingURL=chunk-QH5XB4K6.js.map
|