@triedotdev/mcp 1.0.138 → 1.0.140
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 +184 -38
- package/dist/{autonomy-config-TZ6HF4FA.js → autonomy-config-ZCOSTMPD.js} +2 -2
- package/dist/{chunk-X3F5QDER.js → chunk-4O2KRHK4.js} +934 -132
- package/dist/chunk-4O2KRHK4.js.map +1 -0
- package/dist/{chunk-J5EMP4XW.js → chunk-5KJ4UJOY.js} +9 -4
- package/dist/chunk-5KJ4UJOY.js.map +1 -0
- package/dist/chunk-62POBLFC.js +1925 -0
- package/dist/chunk-62POBLFC.js.map +1 -0
- package/dist/{chunk-GFFUDJMK.js → chunk-75ADWWUF.js} +13 -13
- package/dist/chunk-75ADWWUF.js.map +1 -0
- package/dist/{chunk-D3AS5LY7.js → chunk-7OJ6JIPL.js} +39 -604
- package/dist/chunk-7OJ6JIPL.js.map +1 -0
- package/dist/{chunk-3RRXWX3V.js → chunk-AF2APASP.js} +38 -4
- package/dist/{chunk-3RRXWX3V.js.map → chunk-AF2APASP.js.map} +1 -1
- package/dist/{chunk-QSWUPSLK.js → chunk-FH335WL5.js} +9 -1
- package/dist/chunk-FH335WL5.js.map +1 -0
- package/dist/{chunk-Y32FM3MR.js → chunk-FPEMP54L.js} +21 -15
- package/dist/chunk-FPEMP54L.js.map +1 -0
- package/dist/{chunk-EDDT4ZIH.js → chunk-GXF6JOCN.js} +21 -323
- package/dist/chunk-GXF6JOCN.js.map +1 -0
- package/dist/chunk-LD7ZEFNY.js +132 -0
- package/dist/chunk-LD7ZEFNY.js.map +1 -0
- package/dist/chunk-NKHO34UZ.js +467 -0
- package/dist/chunk-NKHO34UZ.js.map +1 -0
- package/dist/{chunk-YOKQ25IW.js → chunk-OQ4A3RDY.js} +14 -14
- package/dist/{chunk-6LLH3TBZ.js → chunk-UOSTOLU7.js} +12 -12
- package/dist/{chunk-67GSG2ST.js → chunk-XTTZAQWJ.js} +18 -15
- package/dist/chunk-XTTZAQWJ.js.map +1 -0
- package/dist/{chunk-FOCXXIXY.js → chunk-YEIJW6X6.js} +2 -2
- package/dist/chunk-YOJGSRZK.js +216 -0
- package/dist/chunk-YOJGSRZK.js.map +1 -0
- package/dist/cli/main.js +573 -59
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +15 -13
- package/dist/cli/yolo-daemon.js.map +1 -1
- package/dist/{client-JTU5TRLB.js → client-INNE2GGZ.js} +2 -2
- package/dist/{codebase-index-FNJ4GCBE.js → codebase-index-5SEOESWM.js} +3 -3
- package/dist/fast-analyzer-AYLZB5TW.js +216 -0
- package/dist/fast-analyzer-AYLZB5TW.js.map +1 -0
- package/dist/github-ingester-J2ZFYXVE.js +11 -0
- package/dist/{goal-manager-6BJQ36AH.js → goal-manager-ZBWKWEML.js} +3 -3
- package/dist/{goal-validator-GISXYANK.js → goal-validator-HNXXUCPW.js} +3 -3
- package/dist/{graph-X2FMRQLG.js → graph-J4OGTYCO.js} +2 -2
- package/dist/{hypothesis-K3KQJOXJ.js → hypothesis-JCUMZKTG.js} +3 -3
- package/dist/index.js +1090 -108
- package/dist/index.js.map +1 -1
- package/dist/{issue-store-BO5OWLJW.js → issue-store-LZWZIGM7.js} +2 -2
- package/dist/linear-ingester-JRDQAIAA.js +11 -0
- package/dist/linear-ingester-JRDQAIAA.js.map +1 -0
- package/dist/{trie-agent-XMSGMD7E.js → trie-agent-M6PHM6UD.js} +10 -10
- package/dist/trie-agent-M6PHM6UD.js.map +1 -0
- package/package.json +15 -8
- package/dist/chunk-67GSG2ST.js.map +0 -1
- package/dist/chunk-D3AS5LY7.js.map +0 -1
- package/dist/chunk-EDDT4ZIH.js.map +0 -1
- package/dist/chunk-GFFUDJMK.js.map +0 -1
- package/dist/chunk-J5EMP4XW.js.map +0 -1
- package/dist/chunk-QSWUPSLK.js.map +0 -1
- package/dist/chunk-X3F5QDER.js.map +0 -1
- package/dist/chunk-Y32FM3MR.js.map +0 -1
- package/dist/chunk-Z2P4WST6.js +0 -883
- package/dist/chunk-Z2P4WST6.js.map +0 -1
- /package/dist/{autonomy-config-TZ6HF4FA.js.map → autonomy-config-ZCOSTMPD.js.map} +0 -0
- /package/dist/{chunk-YOKQ25IW.js.map → chunk-OQ4A3RDY.js.map} +0 -0
- /package/dist/{chunk-6LLH3TBZ.js.map → chunk-UOSTOLU7.js.map} +0 -0
- /package/dist/{chunk-FOCXXIXY.js.map → chunk-YEIJW6X6.js.map} +0 -0
- /package/dist/{client-JTU5TRLB.js.map → client-INNE2GGZ.js.map} +0 -0
- /package/dist/{codebase-index-FNJ4GCBE.js.map → codebase-index-5SEOESWM.js.map} +0 -0
- /package/dist/{goal-manager-6BJQ36AH.js.map → github-ingester-J2ZFYXVE.js.map} +0 -0
- /package/dist/{goal-validator-GISXYANK.js.map → goal-manager-ZBWKWEML.js.map} +0 -0
- /package/dist/{graph-X2FMRQLG.js.map → goal-validator-HNXXUCPW.js.map} +0 -0
- /package/dist/{hypothesis-K3KQJOXJ.js.map → graph-J4OGTYCO.js.map} +0 -0
- /package/dist/{issue-store-BO5OWLJW.js.map → hypothesis-JCUMZKTG.js.map} +0 -0
- /package/dist/{trie-agent-XMSGMD7E.js.map → issue-store-LZWZIGM7.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/memory/ledger.ts","../src/agent/git.ts","../src/utils/command-runner.ts","../src/skills/audit-logger.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 activeIssues: number; // Unresolved issues\n issuesByAgent: Record<string, number>;\n issuesBySeverity: Record<string, number>; // All issues (historical)\n activeIssuesBySeverity: Record<string, number>; // Only unresolved\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 * Auto-resolve issues that were not found in the latest scan\n * \n * After a scan completes, this function compares new issues against stored issues.\n * Issues that were previously found in scanned files but are no longer detected\n * are automatically marked as resolved.\n * \n * @param newIssueHashes - Set of hashes from the current scan\n * @param scannedFiles - List of files that were scanned (to scope resolution)\n * @param workDir - Working directory\n * @returns Number of issues auto-resolved\n */\nexport async function autoResolveIssues(\n newIssueHashes: Set<string>,\n scannedFiles: string[],\n workDir?: string\n): Promise<{ resolved: number; stillActive: number }> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n \n // Normalize scanned file paths for comparison\n const scannedFileSet = new Set(scannedFiles.map(f => f.replace(/\\\\/g, '/')));\n \n const now = new Date().toISOString();\n let resolvedCount = 0;\n let stillActiveCount = 0;\n \n for (const issue of index) {\n // Skip already resolved issues\n if (issue.resolved) continue;\n \n // Normalize the issue file path\n const normalizedFile = issue.file.replace(/\\\\/g, '/');\n \n // Only auto-resolve issues in files that were scanned\n // This prevents marking issues as resolved if we just did a partial scan\n if (!scannedFileSet.has(normalizedFile)) {\n stillActiveCount++;\n continue;\n }\n \n // If the issue's hash is NOT in the new scan results, it's been fixed\n if (!newIssueHashes.has(issue.hash)) {\n issue.resolved = true;\n issue.resolvedAt = now;\n resolvedCount++;\n } else {\n stillActiveCount++;\n }\n }\n \n // Only save if we resolved something\n if (resolvedCount > 0) {\n await saveIssueIndex(index, projectDir);\n }\n \n return { resolved: resolvedCount, stillActive: stillActiveCount };\n}\n\n/**\n * Resolve goal violation issues for a specific file and goal\n * Called when a goal violation is fixed\n */\nexport async function resolveGoalViolation(\n file: string,\n goalDescription: string,\n workDir?: string\n): Promise<number> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const index = await loadIssueIndex(projectDir);\n \n const now = new Date().toISOString();\n let resolvedCount = 0;\n \n for (const issue of index) {\n if (issue.resolved) continue;\n if (issue.agent !== 'goal-violation') continue;\n \n // Match file and goal description\n const normalizedFile = issue.file.replace(/\\\\/g, '/');\n const normalizedTarget = file.replace(/\\\\/g, '/');\n \n if (normalizedFile === normalizedTarget && \n issue.issue.includes(`Goal \"${goalDescription}\"`)) {\n issue.resolved = true;\n issue.resolvedAt = now;\n resolvedCount++;\n }\n }\n \n if (resolvedCount > 0) {\n await saveIssueIndex(index, projectDir);\n }\n \n return resolvedCount;\n}\n\n/**\n * Get hash for an issue (for external callers)\n */\nexport function getIssueHash(issue: Issue): string {\n return hashIssue(issue);\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 activeIssues: 0,\n issuesByAgent: {},\n issuesBySeverity: {},\n activeIssuesBySeverity: {},\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 \n if (issue.resolved) {\n stats.resolvedCount++;\n } else {\n stats.activeIssues++;\n stats.activeIssuesBySeverity[issue.severity] = (stats.activeIssuesBySeverity[issue.severity] || 0) + 1;\n }\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 * @param options.includeResolved - If false (default), only returns unresolved issues\n */\nexport async function getRecentIssues(\n options: {\n workDir?: string;\n limit?: number;\n daysBack?: number;\n includeResolved?: boolean;\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 const includeResolved = options.includeResolved ?? false;\n \n const cutoff = new Date();\n cutoff.setDate(cutoff.getDate() - daysBack);\n \n return index\n .filter(i => {\n if (new Date(i.timestamp) < cutoff) return false;\n if (!includeResolved && i.resolved) return false;\n return true;\n })\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","import { createHash } from 'crypto';\nimport { mkdir, readFile, writeFile, stat, unlink, readdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { createGzip, createGunzip } from 'zlib';\nimport { pipeline } from 'stream/promises';\nimport { createReadStream, createWriteStream } from 'fs';\nimport { join } from 'path';\nimport { atomicWriteJSON } from '../utils/atomic-write.js';\nimport { getWorkingDirectory, getTrieDirectory } from '../utils/workspace.js';\nimport { getLastCommit, isGitRepo } from '../agent/git.js';\nimport type { StoredIssue } from './issue-store.js';\n\nconst LEDGER_FILENAME = 'ledger.json';\nconst SHARED_LEDGER_DIR = '.trie-shared';\nconst MANIFEST_FILENAME = 'ledger-manifest.json';\nconst SYNC_STATE_FILENAME = 'ledger-sync.json';\nconst GENESIS_HASH = '0'.repeat(64);\nconst LEDGER_VERSION = 2; // Increased for sync support\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\n// Enhanced interfaces for sync functionality\nexport interface SyncableLedgerBlock extends LedgerBlock {\n author: string; // Developer who created block\n gitCommit?: string; // Associated git commit hash\n chainHeight: number; // Block position in chain\n syncedAt?: string; // When block was synced\n conflictResolved?: boolean; // If block resolved conflicts\n}\n\nexport interface CompressedBlock {\n date: string;\n compressedData: string; // gzipped JSON\n originalSize: number;\n compressedSize: number;\n compressionRatio: number;\n entryCount: number;\n blockHash: string;\n author: string;\n}\n\nexport interface LedgerManifest {\n version: number;\n created: string;\n lastSync: string;\n totalBlocks: number;\n totalEntries: number;\n activeBlocks: string[]; // Recent block filenames\n archivedBlocks: string[]; // Archived block filenames\n index: {\n byDate: Record<string, string>; // date → block location\n byAuthor: Record<string, string[]>; // author → block locations\n bySeverity: Record<string, number>; // severity → count\n };\n compressionConfig: {\n enabled: boolean;\n archiveAfterDays: number;\n compressionLevel: number;\n maxHotStorageSize: number; // bytes\n };\n}\n\nexport interface LedgerSyncState {\n lastSyncTimestamp: string;\n lastSyncCommit?: string;\n conflicts: ChainConflict[];\n localChanges: boolean;\n sharedChanges: boolean;\n}\n\nexport interface ChainConflict {\n type: 'divergent_chain' | 'duplicate_entry' | 'hash_mismatch';\n description: string;\n localBlock?: SyncableLedgerBlock;\n remoteBlock?: SyncableLedgerBlock;\n resolution?: 'local' | 'remote' | 'merge' | 'manual';\n}\n\nexport interface ChainMergeResult {\n mergedChain: SyncableLedgerBlock[];\n conflicts: ChainConflict[];\n resolutionStrategy: 'longest' | 'timestamp' | 'manual';\n stats: {\n localBlocks: number;\n remoteBlocks: number;\n mergedBlocks: number;\n duplicatesRemoved: number;\n };\n}\n\nexport async function appendIssuesToLedger(\n issues: StoredIssue[],\n workDir?: string,\n author?: string\n): Promise<SyncableLedgerBlock | 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 // Get git info for author attribution\n const isRepo = await isGitRepo(projectDir);\n const lastCommit = isRepo ? await getLastCommit(projectDir) : null;\n const blockAuthor = author || lastCommit?.author || 'unknown';\n\n const blocks = await loadLedger(projectDir) as SyncableLedgerBlock[];\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 : createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, blockAuthor, lastCommit?.hash, blocks.length);\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\nfunction createSyncableBlock(\n date: string,\n now: string,\n previousHash: string,\n author: string,\n gitCommit?: string,\n chainHeight: number = 0\n): SyncableLedgerBlock {\n return {\n version: LEDGER_VERSION,\n date,\n entries: [],\n previousHash,\n merkleRoot: '',\n blockHash: '',\n createdAt: now,\n updatedAt: now,\n author,\n gitCommit,\n chainHeight,\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\n/** Load ledger blocks for UI display (block hashes, merkle roots, chain) */\nexport async function getLedgerBlocks(workDir?: string): Promise<LedgerBlock[]> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n return loadLedger(projectDir);\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\n// ==================== Shared Storage Functions ====================\n\nfunction getSharedLedgerDir(projectDir: string): string {\n return join(projectDir, SHARED_LEDGER_DIR);\n}\n\nfunction getActiveBlocksDir(projectDir: string): string {\n return join(getSharedLedgerDir(projectDir), 'active');\n}\n\nfunction getArchivedBlocksDir(projectDir: string): string {\n return join(getSharedLedgerDir(projectDir), 'archived');\n}\n\nfunction getManifestPath(projectDir: string): string {\n return join(getSharedLedgerDir(projectDir), MANIFEST_FILENAME);\n}\n\nfunction getSyncStatePath(projectDir: string): string {\n return join(getTrieDirectory(projectDir), 'memory', SYNC_STATE_FILENAME);\n}\n\nasync function ensureSharedStorageStructure(projectDir: string): Promise<void> {\n const sharedDir = getSharedLedgerDir(projectDir);\n const activeDir = getActiveBlocksDir(projectDir);\n const archivedDir = getArchivedBlocksDir(projectDir);\n\n await mkdir(sharedDir, { recursive: true });\n await mkdir(activeDir, { recursive: true });\n await mkdir(archivedDir, { recursive: true });\n}\n\nasync function loadManifest(projectDir: string): Promise<LedgerManifest | null> {\n const manifestPath = getManifestPath(projectDir);\n\n try {\n if (!existsSync(manifestPath)) return null;\n const content = await readFile(manifestPath, 'utf-8');\n return JSON.parse(content) as LedgerManifest;\n } catch {\n return null;\n }\n}\n\nasync function saveManifest(manifest: LedgerManifest, projectDir: string): Promise<void> {\n const manifestPath = getManifestPath(projectDir);\n await atomicWriteJSON(manifestPath, manifest);\n}\n\nasync function createDefaultManifest(projectDir: string): Promise<LedgerManifest> {\n const now = new Date().toISOString();\n\n return {\n version: LEDGER_VERSION,\n created: now,\n lastSync: now,\n totalBlocks: 0,\n totalEntries: 0,\n activeBlocks: [],\n archivedBlocks: [],\n index: {\n byDate: {},\n byAuthor: {},\n bySeverity: {}\n },\n compressionConfig: {\n enabled: true,\n archiveAfterDays: 30,\n compressionLevel: 6,\n maxHotStorageSize: 50 * 1024 * 1024 // 50MB\n }\n };\n}\n\nasync function loadSyncState(projectDir: string): Promise<LedgerSyncState | null> {\n const syncStatePath = getSyncStatePath(projectDir);\n\n try {\n if (!existsSync(syncStatePath)) return null;\n const content = await readFile(syncStatePath, 'utf-8');\n return JSON.parse(content) as LedgerSyncState;\n } catch {\n return null;\n }\n}\n\nasync function saveSyncState(syncState: LedgerSyncState, projectDir: string): Promise<void> {\n const syncStatePath = getSyncStatePath(projectDir);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n await mkdir(memoryDir, { recursive: true });\n await atomicWriteJSON(syncStatePath, syncState);\n}\n\n// ==================== Core Sync Functions ====================\n\nexport async function initializeSharedLedger(workDir?: string): Promise<void> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n await ensureSharedStorageStructure(projectDir);\n\n const existingManifest = await loadManifest(projectDir);\n if (!existingManifest) {\n const manifest = await createDefaultManifest(projectDir);\n await saveManifest(manifest, projectDir);\n }\n\n // Initialize sync state if needed\n const existingSyncState = await loadSyncState(projectDir);\n if (!existingSyncState) {\n const now = new Date().toISOString();\n const syncState: LedgerSyncState = {\n lastSyncTimestamp: now,\n conflicts: [],\n localChanges: false,\n sharedChanges: false\n };\n await saveSyncState(syncState, projectDir);\n }\n}\n\nexport async function syncLedgerFromShared(workDir?: string): Promise<ChainMergeResult> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n\n // Ensure shared storage exists\n await initializeSharedLedger(projectDir);\n\n // Load current state\n const manifest = await loadManifest(projectDir);\n const localBlocks = await loadLedger(projectDir) as SyncableLedgerBlock[];\n const sharedBlocks = await loadSharedBlocks(projectDir);\n\n if (!manifest) {\n throw new Error('Failed to load ledger manifest');\n }\n\n // Merge chains\n const mergeResult = await mergeChains(localBlocks, sharedBlocks, 'timestamp');\n\n // Save merged chain locally\n await saveLedger(mergeResult.mergedChain, projectDir);\n\n // Update sync state\n const syncState: LedgerSyncState = {\n lastSyncTimestamp: new Date().toISOString(),\n conflicts: mergeResult.conflicts,\n localChanges: false,\n sharedChanges: false\n };\n await saveSyncState(syncState, projectDir);\n\n return mergeResult;\n}\n\nexport async function pushLedgerToShared(workDir?: string): Promise<void> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n\n // Ensure shared storage exists\n await initializeSharedLedger(projectDir);\n\n // Load current state\n const localBlocks = await loadLedger(projectDir) as SyncableLedgerBlock[];\n const manifest = await loadManifest(projectDir) || await createDefaultManifest(projectDir);\n\n // Save blocks to shared storage\n const activeDir = getActiveBlocksDir(projectDir);\n\n for (const block of localBlocks) {\n const blockFilename = `${block.date}.json`;\n const blockPath = join(activeDir, blockFilename);\n\n // Only save if not already present or if block has been updated\n if (!existsSync(blockPath) || block.updatedAt > manifest.lastSync) {\n await atomicWriteJSON(blockPath, block);\n\n // Update manifest index\n manifest.index.byDate[block.date] = `active/${blockFilename}`;\n\n if (block.author) {\n if (!manifest.index.byAuthor[block.author]) {\n manifest.index.byAuthor[block.author] = [];\n }\n if (!manifest.index.byAuthor[block.author].includes(`active/${blockFilename}`)) {\n manifest.index.byAuthor[block.author].push(`active/${blockFilename}`);\n }\n }\n\n // Update active blocks list\n if (!manifest.activeBlocks.includes(blockFilename)) {\n manifest.activeBlocks.push(blockFilename);\n }\n }\n }\n\n // Update manifest metadata\n manifest.lastSync = new Date().toISOString();\n manifest.totalBlocks = manifest.activeBlocks.length + manifest.archivedBlocks.length;\n manifest.totalEntries = localBlocks.reduce((sum, block) => sum + block.entries.length, 0);\n\n await saveManifest(manifest, projectDir);\n}\n\nasync function loadSharedBlocks(projectDir: string): Promise<SyncableLedgerBlock[]> {\n const manifest = await loadManifest(projectDir);\n if (!manifest) return [];\n\n const blocks: SyncableLedgerBlock[] = [];\n const activeDir = getActiveBlocksDir(projectDir);\n\n // Load active blocks\n for (const filename of manifest.activeBlocks) {\n const blockPath = join(activeDir, filename);\n try {\n if (existsSync(blockPath)) {\n const content = await readFile(blockPath, 'utf-8');\n const block = JSON.parse(content) as SyncableLedgerBlock;\n blocks.push(block);\n }\n } catch (error) {\n console.warn(`Failed to load shared block ${filename}:`, error);\n }\n }\n\n // TODO: Load archived blocks when needed\n\n // Sort by date to maintain chronological order\n return blocks.sort((a, b) => a.date.localeCompare(b.date));\n}\n\n// ==================== Chain Merge & Conflict Resolution ====================\n\nasync function mergeChains(\n localBlocks: SyncableLedgerBlock[],\n remoteBlocks: SyncableLedgerBlock[],\n strategy: 'longest' | 'timestamp' | 'manual' = 'timestamp'\n): Promise<ChainMergeResult> {\n const conflicts: ChainConflict[] = [];\n const mergedBlocks = new Map<string, SyncableLedgerBlock>();\n const stats = {\n localBlocks: localBlocks.length,\n remoteBlocks: remoteBlocks.length,\n mergedBlocks: 0,\n duplicatesRemoved: 0\n };\n\n // Index blocks by date for quick lookup\n const localByDate = new Map<string, SyncableLedgerBlock>();\n for (const block of localBlocks) {\n localByDate.set(block.date, block);\n }\n\n const remoteByDate = new Map<string, SyncableLedgerBlock>();\n for (const block of remoteBlocks) {\n remoteByDate.set(block.date, block);\n }\n\n // Get all unique dates\n const allDates = new Set([...localByDate.keys(), ...remoteByDate.keys()]);\n\n for (const date of allDates) {\n const localBlock = localByDate.get(date);\n const remoteBlock = remoteByDate.get(date);\n\n if (localBlock && remoteBlock) {\n // Both chains have a block for this date - potential conflict\n const conflict = detectBlockConflict(localBlock, remoteBlock);\n\n if (conflict) {\n conflicts.push(conflict);\n\n // Apply resolution strategy\n const resolvedBlock = resolveConflict(conflict, strategy);\n if (resolvedBlock) {\n mergedBlocks.set(date, resolvedBlock);\n }\n } else {\n // No conflict - merge entries\n const mergedBlock = mergeBlockEntries(localBlock, remoteBlock);\n mergedBlocks.set(date, mergedBlock);\n }\n } else if (localBlock) {\n // Only local block exists\n mergedBlocks.set(date, localBlock);\n } else if (remoteBlock) {\n // Only remote block exists\n mergedBlocks.set(date, remoteBlock);\n }\n }\n\n // Convert to sorted array and recalculate chain heights\n const resultBlocks = Array.from(mergedBlocks.values())\n .sort((a, b) => a.date.localeCompare(b.date))\n .map((block, index) => ({\n ...block,\n chainHeight: index\n }));\n\n stats.mergedBlocks = resultBlocks.length;\n stats.duplicatesRemoved = stats.localBlocks + stats.remoteBlocks - stats.mergedBlocks;\n\n return {\n mergedChain: resultBlocks,\n conflicts,\n resolutionStrategy: strategy,\n stats\n };\n}\n\nfunction detectBlockConflict(\n localBlock: SyncableLedgerBlock,\n remoteBlock: SyncableLedgerBlock\n): ChainConflict | null {\n // Check for hash mismatch (different content for same date)\n if (localBlock.blockHash !== remoteBlock.blockHash) {\n return {\n type: 'hash_mismatch',\n description: `Different block content for date ${localBlock.date}`,\n localBlock,\n remoteBlock\n };\n }\n\n // Check for entry conflicts\n const localEntryHashes = new Set(localBlock.entries.map(e => e.hash));\n const remoteEntryHashes = new Set(remoteBlock.entries.map(e => e.hash));\n\n const hasConflictingEntries = localBlock.entries.some(localEntry => {\n const conflictingRemoteEntry = remoteBlock.entries.find(remoteEntry =>\n remoteEntry.id === localEntry.id && remoteEntry.hash !== localEntry.hash\n );\n return !!conflictingRemoteEntry;\n });\n\n if (hasConflictingEntries) {\n return {\n type: 'duplicate_entry',\n description: `Conflicting entries found for date ${localBlock.date}`,\n localBlock,\n remoteBlock\n };\n }\n\n return null; // No conflict\n}\n\nfunction resolveConflict(\n conflict: ChainConflict,\n strategy: 'longest' | 'timestamp' | 'manual'\n): SyncableLedgerBlock | null {\n if (!conflict.localBlock || !conflict.remoteBlock) {\n return null;\n }\n\n switch (strategy) {\n case 'longest':\n // Choose block with more entries\n return conflict.localBlock.entries.length >= conflict.remoteBlock.entries.length\n ? conflict.localBlock\n : conflict.remoteBlock;\n\n case 'timestamp':\n // Choose block with later update timestamp\n return conflict.localBlock.updatedAt >= conflict.remoteBlock.updatedAt\n ? conflict.localBlock\n : conflict.remoteBlock;\n\n case 'manual':\n // Leave for manual resolution - for now, prefer local\n return { ...conflict.localBlock, conflictResolved: false };\n\n default:\n return conflict.localBlock;\n }\n}\n\nfunction mergeBlockEntries(\n localBlock: SyncableLedgerBlock,\n remoteBlock: SyncableLedgerBlock\n): SyncableLedgerBlock {\n // Combine entries, deduplicating by hash\n const entryMap = new Map<string, LedgerEntry>();\n\n // Add local entries first\n for (const entry of localBlock.entries) {\n entryMap.set(entry.hash, entry);\n }\n\n // Add remote entries (will overwrite locals with same hash)\n for (const entry of remoteBlock.entries) {\n entryMap.set(entry.hash, entry);\n }\n\n const mergedEntries = Array.from(entryMap.values());\n const now = new Date().toISOString();\n\n // Combine author information\n const authors = [localBlock.author, remoteBlock.author].filter(Boolean);\n const combinedAuthor = authors.length > 1 ? authors.join('+') : authors[0] || 'unknown';\n\n return {\n ...localBlock,\n entries: mergedEntries,\n author: combinedAuthor,\n updatedAt: now,\n merkleRoot: computeMerkleRoot(mergedEntries.map(e => e.hash)),\n blockHash: computeBlockHash(\n localBlock.previousHash,\n computeMerkleRoot(mergedEntries.map(e => e.hash)),\n localBlock.date,\n localBlock.version\n )\n };\n}\n\n// ==================== Migration & Legacy Support ====================\n\nexport async function migrateLegacyLedger(workDir?: string): Promise<boolean> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const legacyLedgerPath = join(getTrieDirectory(projectDir), 'memory', LEDGER_FILENAME);\n\n // Check if legacy ledger exists\n if (!existsSync(legacyLedgerPath)) {\n return false; // No legacy ledger to migrate\n }\n\n try {\n // Load legacy blocks\n const legacyBlocks = await loadLedger(projectDir);\n\n // Check if already migrated (v2 format)\n if (legacyBlocks.length > 0 && (legacyBlocks[0] as any).author !== undefined) {\n return false; // Already migrated\n }\n\n console.log(`Migrating legacy ledger with ${legacyBlocks.length} blocks...`);\n\n // Convert legacy blocks to syncable blocks\n const isRepo = await isGitRepo(projectDir);\n const lastCommit = isRepo ? await getLastCommit(projectDir) : null;\n const defaultAuthor = lastCommit?.author || 'legacy-migration';\n\n const migratedBlocks: SyncableLedgerBlock[] = legacyBlocks.map((block, index) => ({\n ...block,\n version: LEDGER_VERSION,\n author: defaultAuthor,\n gitCommit: lastCommit?.hash,\n chainHeight: index,\n syncedAt: new Date().toISOString()\n }));\n\n // Initialize shared storage\n await initializeSharedLedger(projectDir);\n\n // Save migrated blocks locally\n await saveLedger(migratedBlocks, projectDir);\n\n // Push to shared storage\n await pushLedgerToShared(projectDir);\n\n // Create backup of original ledger\n const backupPath = `${legacyLedgerPath}.backup.${Date.now()}`;\n await writeFile(backupPath, JSON.stringify(legacyBlocks, null, 2));\n\n console.log(`✓ Migration complete. Backup saved to ${backupPath}`);\n return true;\n } catch (error) {\n console.error('Failed to migrate legacy ledger:', error);\n return false;\n }\n}\n\nexport async function detectLegacyLedger(workDir?: string): Promise<boolean> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const legacyLedgerPath = join(getTrieDirectory(projectDir), 'memory', LEDGER_FILENAME);\n\n if (!existsSync(legacyLedgerPath)) {\n return false;\n }\n\n try {\n const blocks = await loadLedger(projectDir);\n return blocks.length > 0 && (blocks[0] as any).author === undefined;\n } catch {\n return false;\n }\n}\n\n// ==================== Status & Info Functions ====================\n\nexport async function getLedgerSyncStatus(workDir?: string): Promise<{\n isInitialized: boolean;\n hasLegacyLedger: boolean;\n syncState: LedgerSyncState | null;\n manifest: LedgerManifest | null;\n localBlocks: number;\n sharedBlocks: number;\n conflicts: number;\n}> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n\n const hasLegacyLedger = await detectLegacyLedger(projectDir);\n const manifest = await loadManifest(projectDir);\n const syncState = await loadSyncState(projectDir);\n const localBlocks = await loadLedger(projectDir);\n const sharedBlocks = await loadSharedBlocks(projectDir);\n\n return {\n isInitialized: !!manifest,\n hasLegacyLedger,\n syncState,\n manifest,\n localBlocks: localBlocks.length,\n sharedBlocks: sharedBlocks.length,\n conflicts: syncState?.conflicts.length || 0\n };\n}\n\n// ==================== Compression & Archival System ====================\n\nexport async function compressOldBlocks(workDir?: string): Promise<{\n archived: number;\n sizeReduction: number;\n}> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const manifest = await loadManifest(projectDir);\n\n if (!manifest || !manifest.compressionConfig.enabled) {\n return { archived: 0, sizeReduction: 0 };\n }\n\n const activeDir = getActiveBlocksDir(projectDir);\n const archivedDir = getArchivedBlocksDir(projectDir);\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - manifest.compressionConfig.archiveAfterDays);\n\n let archivedCount = 0;\n let originalSize = 0;\n let compressedSize = 0;\n\n // Group blocks by month for archival\n const blocksByMonth = new Map<string, string[]>();\n\n for (const blockFile of manifest.activeBlocks) {\n const blockPath = join(activeDir, blockFile);\n const blockDate = blockFile.replace('.json', '');\n\n if (new Date(blockDate) < cutoffDate) {\n const monthKey = blockDate.slice(0, 7); // YYYY-MM\n if (!blocksByMonth.has(monthKey)) {\n blocksByMonth.set(monthKey, []);\n }\n blocksByMonth.get(monthKey)!.push(blockFile);\n }\n }\n\n // Archive each month\n for (const [monthKey, blockFiles] of blocksByMonth) {\n const archivePath = join(archivedDir, `${monthKey}.tar.gz`);\n\n // Skip if already archived\n if (existsSync(archivePath)) {\n continue;\n }\n\n console.log(`Archiving ${blockFiles.length} blocks for ${monthKey}...`);\n\n const monthlyBlocks: SyncableLedgerBlock[] = [];\n for (const blockFile of blockFiles) {\n const blockPath = join(activeDir, blockFile);\n\n try {\n const stats = await stat(blockPath);\n originalSize += stats.size;\n\n const content = await readFile(blockPath, 'utf-8');\n const block = JSON.parse(content) as SyncableLedgerBlock;\n monthlyBlocks.push(block);\n } catch (error) {\n console.warn(`Failed to read block ${blockFile}:`, error);\n }\n }\n\n // Compress and write archive\n if (monthlyBlocks.length > 0) {\n const archiveData = JSON.stringify(monthlyBlocks);\n const tempPath = `${archivePath}.tmp`;\n\n // Write compressed archive\n await pipeline(\n Buffer.from(archiveData),\n createGzip({ level: manifest.compressionConfig.compressionLevel }),\n createWriteStream(tempPath)\n );\n\n // Get compressed size\n const compressedStats = await stat(tempPath);\n compressedSize += compressedStats.size;\n\n // Rename to final location\n await writeFile(archivePath, await readFile(tempPath));\n await unlink(tempPath);\n\n // Remove original block files\n for (const blockFile of blockFiles) {\n const blockPath = join(activeDir, blockFile);\n await unlink(blockPath);\n\n // Remove from manifest\n const index = manifest.activeBlocks.indexOf(blockFile);\n if (index > -1) {\n manifest.activeBlocks.splice(index, 1);\n }\n }\n\n // Add to archived blocks\n manifest.archivedBlocks.push(`${monthKey}.tar.gz`);\n archivedCount += blockFiles.length;\n }\n }\n\n // Update manifest\n if (archivedCount > 0) {\n await saveManifest(manifest, projectDir);\n }\n\n return {\n archived: archivedCount,\n sizeReduction: originalSize > 0 ? Math.round(((originalSize - compressedSize) / originalSize) * 100) : 0\n };\n}\n\nasync function loadArchivedBlocks(\n projectDir: string,\n monthKey: string\n): Promise<SyncableLedgerBlock[]> {\n const archivedDir = getArchivedBlocksDir(projectDir);\n const archivePath = join(archivedDir, `${monthKey}.tar.gz`);\n\n if (!existsSync(archivePath)) {\n return [];\n }\n\n try {\n // Decompress and parse\n const chunks: Buffer[] = [];\n await pipeline(\n createReadStream(archivePath),\n createGunzip(),\n async function* (source) {\n for await (const chunk of source) {\n chunks.push(chunk);\n }\n yield Buffer.concat(chunks);\n }\n );\n\n const decompressedData = Buffer.concat(chunks).toString('utf-8');\n return JSON.parse(decompressedData) as SyncableLedgerBlock[];\n } catch (error) {\n console.error(`Failed to load archived blocks for ${monthKey}:`, error);\n return [];\n }\n}\n\nexport async function getStorageStats(workDir?: string): Promise<{\n activeBlocks: number;\n archivedBlocks: number;\n activeSize: number;\n archivedSize: number;\n compressionRatio: number;\n totalEntries: number;\n}> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const manifest = await loadManifest(projectDir);\n\n if (!manifest) {\n return {\n activeBlocks: 0,\n archivedBlocks: 0,\n activeSize: 0,\n archivedSize: 0,\n compressionRatio: 0,\n totalEntries: 0\n };\n }\n\n const activeDir = getActiveBlocksDir(projectDir);\n const archivedDir = getArchivedBlocksDir(projectDir);\n\n let activeSize = 0;\n let archivedSize = 0;\n\n // Calculate active storage size\n for (const blockFile of manifest.activeBlocks) {\n const blockPath = join(activeDir, blockFile);\n try {\n if (existsSync(blockPath)) {\n const stats = await stat(blockPath);\n activeSize += stats.size;\n }\n } catch {\n // Ignore missing files\n }\n }\n\n // Calculate archived storage size\n for (const archiveFile of manifest.archivedBlocks) {\n const archivePath = join(archivedDir, archiveFile);\n try {\n if (existsSync(archivePath)) {\n const stats = await stat(archivePath);\n archivedSize += stats.size;\n }\n } catch {\n // Ignore missing files\n }\n }\n\n const totalSize = activeSize + archivedSize;\n const estimatedUncompressed = archivedSize * 5; // Rough estimate\n const compressionRatio = estimatedUncompressed > 0\n ? Math.round((1 - (archivedSize / estimatedUncompressed)) * 100)\n : 0;\n\n return {\n activeBlocks: manifest.activeBlocks.length,\n archivedBlocks: manifest.archivedBlocks.length,\n activeSize,\n archivedSize,\n compressionRatio,\n totalEntries: manifest.totalEntries\n };\n}\n\nexport async function shouldCompress(workDir?: string): Promise<boolean> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const manifest = await loadManifest(projectDir);\n\n if (!manifest || !manifest.compressionConfig.enabled) {\n return false;\n }\n\n const stats = await getStorageStats(projectDir);\n\n // Compress if hot storage exceeds limit or if old blocks exist\n const exceedsSize = stats.activeSize > manifest.compressionConfig.maxHotStorageSize;\n const hasOldBlocks = manifest.activeBlocks.some(blockFile => {\n const blockDate = blockFile.replace('.json', '');\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - manifest.compressionConfig.archiveAfterDays);\n return new Date(blockDate) < cutoffDate;\n });\n\n return exceedsSize || hasOldBlocks;\n}\n\n// ==================== Block Deletion Functions ====================\n\nexport interface DeleteBlockResult {\n success: boolean;\n deletedBlocks: number;\n error?: string;\n warning?: string;\n}\n\n/**\n * Delete specific blocks by date from the ledger\n * WARNING: This is a permanent operation that cannot be undone\n */\nexport async function deleteBlocks(\n blockDates: string[],\n workDir?: string,\n confirmDeletion: boolean = false\n): Promise<DeleteBlockResult> {\n if (!confirmDeletion) {\n return {\n success: false,\n deletedBlocks: 0,\n error: 'Deletion not confirmed. This is a permanent operation that cannot be undone.'\n };\n }\n\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const blocks = await loadLedger(projectDir) as SyncableLedgerBlock[];\n\n if (blocks.length === 0) {\n return {\n success: false,\n deletedBlocks: 0,\n error: 'No blocks found in ledger'\n };\n }\n\n // Find blocks to delete\n const blocksToDelete = blocks.filter(block => blockDates.includes(block.date));\n const remainingBlocks = blocks.filter(block => !blockDates.includes(block.date));\n\n if (blocksToDelete.length === 0) {\n return {\n success: false,\n deletedBlocks: 0,\n error: 'No matching blocks found for the specified dates'\n };\n }\n\n // Check if deleting these blocks would break chain integrity\n const integrityIssue = checkChainIntegrityAfterDeletion(blocks, blockDates);\n if (integrityIssue) {\n return {\n success: false,\n deletedBlocks: 0,\n error: `Cannot delete blocks: ${integrityIssue}`\n };\n }\n\n try {\n // Recalculate chain for remaining blocks\n const repairedChain = repairChainAfterDeletion(remainingBlocks);\n\n // Save the updated ledger\n await saveLedger(repairedChain, projectDir);\n\n // Also clean up from shared storage if it exists\n await cleanupSharedStorage(blockDates, projectDir);\n\n return {\n success: true,\n deletedBlocks: blocksToDelete.length,\n warning: remainingBlocks.length === 0 ? 'All blocks have been deleted. Ledger is now empty.' : undefined\n };\n } catch (error) {\n return {\n success: false,\n deletedBlocks: 0,\n error: `Failed to delete blocks: ${error instanceof Error ? error.message : 'Unknown error'}`\n };\n }\n}\n\n/**\n * Delete all blocks in the ledger\n * WARNING: This completely clears the ledger and cannot be undone\n */\nexport async function deleteAllBlocks(\n workDir?: string,\n confirmDeletion: boolean = false\n): Promise<DeleteBlockResult> {\n if (!confirmDeletion) {\n return {\n success: false,\n deletedBlocks: 0,\n error: 'Deletion not confirmed. This will permanently delete ALL blocks and cannot be undone.'\n };\n }\n\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const blocks = await loadLedger(projectDir);\n\n if (blocks.length === 0) {\n return {\n success: true,\n deletedBlocks: 0,\n warning: 'Ledger is already empty'\n };\n }\n\n try {\n // Save empty ledger\n await saveLedger([], projectDir);\n\n // Clean up shared storage\n await cleanupAllSharedStorage(projectDir);\n\n return {\n success: true,\n deletedBlocks: blocks.length,\n warning: 'All blocks have been permanently deleted. Ledger is now empty.'\n };\n } catch (error) {\n return {\n success: false,\n deletedBlocks: 0,\n error: `Failed to delete all blocks: ${error instanceof Error ? error.message : 'Unknown error'}`\n };\n }\n}\n\n/**\n * Check if deleting specific blocks would break chain integrity\n */\nfunction checkChainIntegrityAfterDeletion(\n blocks: LedgerBlock[],\n datesToDelete: string[]\n): string | null {\n const sortedBlocks = blocks.sort((a, b) => a.date.localeCompare(b.date));\n const deleteIndices = new Set<number>();\n\n // Find indices of blocks to delete\n sortedBlocks.forEach((block, index) => {\n if (datesToDelete.includes(block.date)) {\n deleteIndices.add(index);\n }\n });\n\n // Check if we're deleting the genesis block (first block)\n if (deleteIndices.has(0) && sortedBlocks.length > 1) {\n return 'Cannot delete the genesis block when other blocks exist. This would break the chain.';\n }\n\n // Check for gaps that would break the chain\n for (let i = 1; i < sortedBlocks.length; i++) {\n const currentBlock = sortedBlocks[i];\n const previousBlock = sortedBlocks[i - 1];\n\n // If current block is not being deleted but previous block is being deleted\n if (!deleteIndices.has(i) && deleteIndices.has(i - 1)) {\n // Find the last non-deleted block before this one\n let lastValidIndex = i - 2;\n while (lastValidIndex >= 0 && deleteIndices.has(lastValidIndex)) {\n lastValidIndex--;\n }\n\n if (lastValidIndex >= 0) {\n const expectedPreviousHash = sortedBlocks[lastValidIndex].blockHash;\n if (currentBlock.previousHash !== expectedPreviousHash) {\n return `Deleting block ${previousBlock.date} would break the chain. Block ${currentBlock.date} references it.`;\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Repair chain after deletion by recalculating hashes\n */\nfunction repairChainAfterDeletion(remainingBlocks: SyncableLedgerBlock[]): SyncableLedgerBlock[] {\n if (remainingBlocks.length === 0) {\n return [];\n }\n\n const sortedBlocks = remainingBlocks.sort((a, b) => a.date.localeCompare(b.date));\n\n // Recalculate chain\n for (let i = 0; i < sortedBlocks.length; i++) {\n const block = sortedBlocks[i];\n const previousHash = i === 0 ? GENESIS_HASH : sortedBlocks[i - 1].blockHash;\n\n // Update previous hash reference\n block.previousHash = previousHash;\n\n // Recalculate block hash\n block.blockHash = computeBlockHash(\n block.previousHash,\n block.merkleRoot,\n block.date,\n block.version\n );\n\n // Update chain height\n block.chainHeight = i;\n\n // Update timestamp\n block.updatedAt = new Date().toISOString();\n }\n\n return sortedBlocks;\n}\n\n/**\n * Clean up deleted blocks from shared storage\n */\nasync function cleanupSharedStorage(deletedDates: string[], projectDir: string): Promise<void> {\n const manifest = await loadManifest(projectDir);\n if (!manifest) return;\n\n const activeDir = getActiveBlocksDir(projectDir);\n const archivedDir = getArchivedBlocksDir(projectDir);\n\n // Remove from active blocks\n for (const date of deletedDates) {\n const blockFile = `${date}.json`;\n const blockPath = join(activeDir, blockFile);\n\n if (existsSync(blockPath)) {\n try {\n await unlink(blockPath);\n } catch {\n // Ignore errors - file might already be gone\n }\n }\n\n // Remove from manifest\n const index = manifest.activeBlocks.indexOf(blockFile);\n if (index > -1) {\n manifest.activeBlocks.splice(index, 1);\n }\n\n // Remove from index\n delete manifest.index.byDate[date];\n }\n\n // Update manifest\n manifest.totalBlocks = manifest.activeBlocks.length + manifest.archivedBlocks.length;\n await saveManifest(manifest, projectDir);\n}\n\n/**\n * Clean up all shared storage\n */\nasync function cleanupAllSharedStorage(projectDir: string): Promise<void> {\n const sharedDir = getSharedLedgerDir(projectDir);\n\n if (existsSync(sharedDir)) {\n try {\n // Reset manifest\n const manifest = await createDefaultManifest(projectDir);\n await saveManifest(manifest, projectDir);\n\n // Remove all active block files\n const activeDir = getActiveBlocksDir(projectDir);\n if (existsSync(activeDir)) {\n const files = await readdir(activeDir).catch(() => []);\n for (const file of files) {\n if (file.endsWith('.json')) {\n try {\n await unlink(join(activeDir, file));\n } catch {\n // Ignore cleanup errors\n }\n }\n }\n }\n } catch {\n // Ignore cleanup errors\n }\n }\n}\n","import { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { runExecFile } from '../utils/command-runner.js';\n\nexport interface Commit {\n hash: string;\n author: string;\n date: string;\n message: string;\n}\n\nexport interface Change {\n path: string;\n status: string;\n oldPath?: string;\n}\n\nasync function execGit(args: string[], cwd: string): Promise<string | null> {\n try {\n const { stdout } = await runExecFile(\n 'git',\n ['-C', cwd, ...args],\n { actor: 'internal:git', triggeredBy: 'manual', targetPath: cwd },\n { maxBuffer: 10 * 1024 * 1024, captureOutput: false }\n );\n return stdout.trim();\n } catch (error: any) {\n const stderr: string | undefined = error?.stderr?.toString();\n // Gracefully handle non-git directories and repos with no commits\n if (stderr?.includes('not a git repository') || stderr?.includes('does not have any commits')) {\n return null;\n }\n throw error;\n }\n}\n\nasync function ensureRepo(projectPath: string): Promise<boolean> {\n const result = await execGit(['rev-parse', '--is-inside-work-tree'], projectPath);\n return result === 'true';\n}\n\nfunction parseNameStatus(output: string): Change[] {\n return output\n .split('\\n')\n .map((line) => line.trim())\n .filter(Boolean)\n .map((line) => {\n const parts = line.split('\\t');\n const status = parts[0] ?? '';\n const filePath = parts[1] ?? '';\n const oldPath = parts[2];\n const change: Change = { status, path: filePath };\n if (oldPath) change.oldPath = oldPath;\n return change;\n })\n .filter((entry) => entry.path.length > 0);\n}\n\nexport async function getRecentCommits(projectPath: string, limit: number): Promise<Commit[]> {\n const isRepo = await ensureRepo(projectPath);\n if (!isRepo) return [];\n\n const output = await execGit(\n ['log', `-n`, String(limit), '--pretty=format:%H%x09%an%x09%ad%x09%s', '--date=iso'],\n projectPath\n );\n\n if (!output) return [];\n\n return output.split('\\n').map((line) => {\n const [hash, author, date, message] = line.split('\\t');\n return { hash, author, date, message } as Commit;\n });\n}\n\nexport async function getLastCommit(projectPath: string): Promise<Commit | null> {\n const commits = await getRecentCommits(projectPath, 1);\n return commits[0] ?? null;\n}\n\nexport async function getStagedChanges(projectPath: string): Promise<Change[]> {\n const isRepo = await ensureRepo(projectPath);\n if (!isRepo) return [];\n\n const output = await execGit(['diff', '--cached', '--name-status'], projectPath);\n if (!output) return [];\n return parseNameStatus(output);\n}\n\nexport async function getUncommittedChanges(projectPath: string): Promise<Change[]> {\n const isRepo = await ensureRepo(projectPath);\n if (!isRepo) return [];\n\n const changes: Change[] = [];\n\n const unstaged = await execGit(['diff', '--name-status'], projectPath);\n if (unstaged) {\n changes.push(...parseNameStatus(unstaged));\n }\n\n const untracked = await execGit(['ls-files', '--others', '--exclude-standard'], projectPath);\n if (untracked) {\n changes.push(\n ...untracked\n .split('\\n')\n .map((p) => p.trim())\n .filter(Boolean)\n .map((p) => ({ status: '??', path: p }))\n );\n }\n\n return changes;\n}\n\n/**\n * Get a flat list of changed file paths in the working tree.\n * Convenience helper used by tooling (e.g. cache invalidation).\n *\n * Returns null if not a git repository.\n */\nexport async function getGitChangedFiles(projectPath: string): Promise<string[] | null> {\n const isRepo = await ensureRepo(projectPath);\n if (!isRepo) return null;\n\n const [staged, uncommitted] = await Promise.all([\n getStagedChanges(projectPath).catch(() => []),\n getUncommittedChanges(projectPath).catch(() => []),\n ]);\n\n const paths = new Set<string>();\n for (const change of [...staged, ...uncommitted]) {\n if (change.path) paths.add(change.path);\n if (change.oldPath) paths.add(change.oldPath);\n }\n\n return [...paths];\n}\n\nexport async function getDiff(projectPath: string, commitHash: string): Promise<string> {\n const isRepo = await ensureRepo(projectPath);\n if (!isRepo) return '';\n\n const diff = await execGit(['show', commitHash, '--unified=3', '--no-color'], projectPath);\n return diff ?? '';\n}\n\nexport async function getWorkingTreeDiff(projectPath: string, stagedOnly = false): Promise<string> {\n const isRepo = await ensureRepo(projectPath);\n if (!isRepo) return '';\n\n const args = stagedOnly ? ['diff', '--cached', '--unified=3', '--no-color'] : ['diff', '--unified=3', '--no-color'];\n const diff = await execGit(args, projectPath);\n return diff ?? '';\n}\n\nexport async function getUnpushedCommits(projectPath: string): Promise<Commit[]> {\n const isRepo = await ensureRepo(projectPath);\n if (!isRepo) return [];\n\n // Handles detached HEAD by falling back to HEAD if upstream missing\n const upstream = await execGit(['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'], projectPath);\n if (!upstream) {\n return getRecentCommits(projectPath, 10);\n }\n\n const output = await execGit(['log', `${upstream}..HEAD`, '--pretty=format:%H%x09%an%x09%ad%x09%s', '--date=iso'], projectPath);\n if (!output) return [];\n\n return output.split('\\n').filter(Boolean).map((line) => {\n const [hash, author, date, message] = line.split('\\t');\n return { hash, author, date, message } as Commit;\n });\n}\n\nexport function resolveRepoPath(projectPath: string): string {\n const gitDir = path.join(projectPath, '.git');\n if (existsSync(gitDir)) return projectPath;\n return projectPath;\n}\n\n/**\n * Check if the given path is inside a git repository\n */\nexport async function isGitRepo(projectPath: string): Promise<boolean> {\n const result = await execGit(['rev-parse', '--is-inside-work-tree'], projectPath);\n return result === 'true';\n}\n\n/**\n * Get files changed since a given timestamp\n * Uses git log to find commits after timestamp, then gets affected files\n * Returns null if not a git repo or on error\n */\nexport async function getChangedFilesSinceTimestamp(\n projectPath: string,\n timestamp: number\n): Promise<string[] | null> {\n const isRepo = await isGitRepo(projectPath);\n if (!isRepo) return null;\n\n try {\n // Convert timestamp to ISO date for git\n const sinceDate = new Date(timestamp).toISOString();\n \n // Set timeout for git operations (5 seconds total)\n const GIT_TIMEOUT_MS = 5000;\n const startTime = Date.now();\n \n // Get all files that changed in commits since the timestamp\n // Use Promise.race to timeout if git operations take too long\n const committedChangesPromise = execGit(\n ['log', `--since=${sinceDate}`, '--name-only', '--pretty=format:'],\n projectPath\n );\n const committedChangesTimeout = new Promise<string | null>((resolve) => {\n setTimeout(() => resolve(null), GIT_TIMEOUT_MS);\n });\n const committedChanges = await Promise.race([committedChangesPromise, committedChangesTimeout]);\n\n // Check if we've exceeded timeout\n if (Date.now() - startTime > GIT_TIMEOUT_MS) {\n return null;\n }\n\n // Get currently modified files (staged + unstaged) - run in parallel with timeout\n const stagedPromise = execGit(['diff', '--cached', '--name-only'], projectPath);\n const unstagedPromise = execGit(['diff', '--name-only'], projectPath);\n const untrackedPromise = execGit(\n ['ls-files', '--others', '--exclude-standard'],\n projectPath\n );\n \n const timeoutPromise = new Promise<null>((resolve) => {\n setTimeout(() => resolve(null), Math.max(0, GIT_TIMEOUT_MS - (Date.now() - startTime)));\n });\n \n const [stagedChanges, unstagedChanges, untrackedFiles] = await Promise.race([\n Promise.all([stagedPromise, unstagedPromise, untrackedPromise]),\n timeoutPromise.then(() => [null, null, null] as const)\n ]);\n\n // Combine all changed files\n const changedFiles = new Set<string>();\n \n const addFiles = (output: string | null) => {\n if (output) {\n output.split('\\n')\n .map(f => f.trim())\n .filter(Boolean)\n .forEach(f => changedFiles.add(path.join(projectPath, f)));\n }\n };\n\n addFiles(committedChanges);\n addFiles(stagedChanges);\n addFiles(unstagedChanges);\n addFiles(untrackedFiles);\n\n return Array.from(changedFiles);\n } catch {\n return null;\n }\n}\n","/**\n * Command Runner (with audit logging)\n *\n * Goal: Whenever Trie runs a shell command, record:\n * - command string\n * - exit code\n * - duration\n * - optional (redacted) stdout/stderr\n */\nimport { exec, execFile, execSync, type ExecException } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nimport {\n createAuditEntry,\n completeAuditEntry,\n logSkillExecution,\n type ExecutedCommand,\n type SkillExecution,\n} from '../skills/audit-logger.js';\n\nconst execAsync = promisify(exec);\nconst execFileAsync = promisify(execFile);\n\nexport type { ExecutedCommand, SkillExecution };\nexport type AuditTriggeredBy = SkillExecution['triggeredBy'];\n\nexport interface CommandAuditContext {\n /** Shown as `skillName` in audit logs; use something like `tool:pr-review` */\n actor: string;\n /** Where this came from in the product flow */\n triggeredBy: AuditTriggeredBy;\n /** Usually the working directory / repo path */\n targetPath: string;\n /** Optional string for `skillSource` */\n source?: string;\n}\n\nexport interface RunCommandOptions {\n cwd?: string;\n timeoutMs?: number;\n maxBuffer?: number;\n\n /** Capture stdout/stderr in the audit log */\n captureOutput?: boolean;\n /** Redact obvious secrets from captured output */\n redactOutput?: boolean;\n /** Max chars to keep per output stream */\n maxOutputChars?: number;\n}\n\nfunction redact(text: string): string {\n // Keep this conservative to avoid false redaction and avoid expensive processing.\n return text\n // Common key=value secrets\n .replace(/\\b(AWS|ANTHROPIC|OPENAI|GITHUB)_[A-Z0-9_]*\\s*=\\s*([^\\s\"'`]+)/gi, '$1_<REDACTED>=<REDACTED>')\n // Bearer tokens\n .replace(/\\bBearer\\s+[A-Za-z0-9\\-._~+/]+=*\\b/g, 'Bearer <REDACTED>')\n // GitHub tokens / generic tokens\n .replace(/\\bghp_[A-Za-z0-9]{20,}\\b/g, 'ghp_<REDACTED>')\n .replace(/\\b(?:xox[baprs]-)[A-Za-z0-9-]{10,}\\b/g, '<REDACTED_SLACK_TOKEN>')\n // AWS access key id (best-effort)\n .replace(/\\bAKIA[0-9A-Z]{16}\\b/g, 'AKIA<REDACTED>');\n}\n\nfunction clampOutput(text: string, maxChars: number): string {\n if (text.length <= maxChars) return text;\n return text.slice(0, maxChars) + `\\n…(truncated ${text.length - maxChars} chars)`;\n}\n\nfunction buildCommandRecord(command: string): ExecutedCommand {\n return {\n command,\n timestamp: new Date().toISOString(),\n };\n}\n\nasync function finalizeAndWrite(\n entry: SkillExecution,\n cmd: ExecutedCommand,\n outcome: { success: boolean; exitCode?: number; stdout?: string; stderr?: string; error?: string; startedAt: number },\n options?: Pick<RunCommandOptions, 'captureOutput' | 'redactOutput' | 'maxOutputChars'>\n): Promise<void> {\n const duration = Date.now() - outcome.startedAt;\n cmd.duration = duration;\n if (outcome.exitCode !== undefined) {\n cmd.exitCode = outcome.exitCode;\n }\n\n const captureOutput = options?.captureOutput ?? false;\n const redactOutput = options?.redactOutput ?? true;\n const maxOutputChars = options?.maxOutputChars ?? 2000;\n\n if (captureOutput) {\n const out = outcome.stdout ?? '';\n const err = outcome.stderr ?? '';\n cmd.stdout = redactOutput ? redact(clampOutput(out, maxOutputChars)) : clampOutput(out, maxOutputChars);\n cmd.stderr = redactOutput ? redact(clampOutput(err, maxOutputChars)) : clampOutput(err, maxOutputChars);\n }\n\n const completed = completeAuditEntry(entry, outcome.success, outcome.error);\n await logSkillExecution(completed);\n}\n\nexport async function runShellCommand(\n command: string,\n audit: CommandAuditContext,\n options?: RunCommandOptions\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n const startedAt = Date.now();\n const entry = createAuditEntry(audit.actor, audit.source ?? 'trie', audit.triggeredBy, audit.targetPath);\n const cmd = buildCommandRecord(command);\n entry.commands?.push(cmd);\n\n try {\n const { stdout, stderr } = await execAsync(command, {\n cwd: options?.cwd,\n timeout: options?.timeoutMs,\n maxBuffer: options?.maxBuffer,\n });\n\n await finalizeAndWrite(entry, cmd, { success: true, exitCode: 0, stdout, stderr, startedAt }, options);\n return { stdout: stdout ?? '', stderr: stderr ?? '', exitCode: 0 };\n } catch (e) {\n const err = e as ExecException & { stdout?: unknown; stderr?: unknown; code?: unknown };\n const stdout = typeof err.stdout === 'string' ? err.stdout : '';\n const stderr = typeof err.stderr === 'string' ? err.stderr : '';\n const exitCode = typeof err.code === 'number' ? err.code : 1;\n\n await finalizeAndWrite(\n entry,\n cmd,\n { success: false, exitCode, stdout, stderr, error: err.message, startedAt },\n // Capture output for failures by default (so audits are useful)\n { ...options, captureOutput: options?.captureOutput ?? true }\n );\n\n return { stdout, stderr, exitCode };\n }\n}\n\nexport function runShellCommandSync(\n command: string,\n audit: CommandAuditContext,\n options?: Omit<RunCommandOptions, 'timeoutMs'> & { timeoutMs?: number }\n): { stdout: string; exitCode: number } {\n const startedAt = Date.now();\n const entry = createAuditEntry(audit.actor, audit.source ?? 'trie', audit.triggeredBy, audit.targetPath);\n const cmd = buildCommandRecord(command);\n entry.commands?.push(cmd);\n\n try {\n const stdout = execSync(command, {\n cwd: options?.cwd,\n timeout: options?.timeoutMs,\n maxBuffer: options?.maxBuffer,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n // Fire-and-forget write; sync APIs can’t await.\n void finalizeAndWrite(entry, cmd, { success: true, exitCode: 0, stdout, stderr: '', startedAt }, options);\n return { stdout: stdout ?? '', exitCode: 0 };\n } catch (e) {\n const err = e as ExecException & { stdout?: unknown; stderr?: unknown; status?: unknown };\n const stdout = typeof err.stdout === 'string' ? err.stdout : '';\n const stderr = typeof err.stderr === 'string' ? err.stderr : '';\n const exitCode = typeof err.status === 'number' ? err.status : 1;\n\n void finalizeAndWrite(\n entry,\n cmd,\n { success: false, exitCode, stdout, stderr, error: err.message, startedAt },\n { ...options, captureOutput: options?.captureOutput ?? true }\n );\n\n return { stdout, exitCode };\n }\n}\n\nexport async function runExecFile(\n file: string,\n args: string[],\n audit: CommandAuditContext,\n options?: Omit<RunCommandOptions, 'timeoutMs'> & { timeoutMs?: number }\n): Promise<{ stdout: string; stderr: string; exitCode: number }> {\n const startedAt = Date.now();\n const command = [file, ...args].join(' ');\n const entry = createAuditEntry(audit.actor, audit.source ?? 'trie', audit.triggeredBy, audit.targetPath);\n const cmd = buildCommandRecord(command);\n entry.commands?.push(cmd);\n\n try {\n const { stdout, stderr } = await execFileAsync(file, args, {\n cwd: options?.cwd,\n timeout: options?.timeoutMs,\n maxBuffer: options?.maxBuffer,\n });\n\n await finalizeAndWrite(entry, cmd, { success: true, exitCode: 0, stdout: String(stdout ?? ''), stderr: String(stderr ?? ''), startedAt }, options);\n return { stdout: String(stdout ?? ''), stderr: String(stderr ?? ''), exitCode: 0 };\n } catch (e) {\n const err = e as ExecException & { stdout?: unknown; stderr?: unknown; code?: unknown };\n const stdout = typeof err.stdout === 'string' ? err.stdout : '';\n const stderr = typeof err.stderr === 'string' ? err.stderr : '';\n const exitCode = typeof err.code === 'number' ? err.code : 1;\n\n await finalizeAndWrite(\n entry,\n cmd,\n { success: false, exitCode, stdout, stderr, error: err.message, startedAt },\n { ...options, captureOutput: options?.captureOutput ?? true }\n );\n return { stdout, stderr, exitCode };\n }\n}\n\n","/**\n * Audit logger stub\n * Audit functionality has been integrated into decision ledger\n */\n\nexport interface AuditStatistics {\n totalScans: number;\n totalIssues: number;\n criticalCount: number;\n seriousCount: number;\n moderateCount: number;\n lowCount: number;\n totalExecutions: number;\n successfulExecutions: number;\n failedExecutions: number;\n uniqueSkills: number;\n totalCommands: number;\n blockedCommands: number;\n totalNetworkCalls: number;\n blockedNetworkCalls: number;\n}\n\nexport interface AuditEntry {\n id: string;\n timestamp: string;\n command: string;\n status: string;\n commands?: ExecutedCommand[];\n}\n\nexport interface ExecutedCommand {\n command: string;\n timestamp: string;\n exitCode?: number;\n duration?: number;\n stdout?: string;\n stderr?: string;\n}\n\nexport interface SkillExecution {\n skillName: string;\n skillSource: string;\n triggeredBy: 'scan' | 'mcp' | 'cli' | 'watch' | 'manual';\n targetPath: string;\n startedAt: string;\n completedAt?: string;\n success?: boolean;\n error?: string;\n commands?: ExecutedCommand[];\n}\n\nexport function formatAuditLog(_entry: AuditEntry): string {\n return 'Audit logging has been integrated into the decision ledger';\n}\n\nexport function getAuditStatistics(): AuditStatistics {\n return {\n totalScans: 0,\n totalIssues: 0,\n criticalCount: 0,\n seriousCount: 0,\n moderateCount: 0,\n lowCount: 0,\n totalExecutions: 0,\n successfulExecutions: 0,\n failedExecutions: 0,\n uniqueSkills: 0,\n totalCommands: 0,\n blockedCommands: 0,\n totalNetworkCalls: 0,\n blockedNetworkCalls: 0,\n };\n}\n\nexport function createAuditEntry(\n skillName: string, \n skillSource: string, \n triggeredBy: SkillExecution['triggeredBy'], \n targetPath: string\n): SkillExecution {\n return {\n skillName,\n skillSource,\n triggeredBy,\n targetPath,\n startedAt: new Date().toISOString(),\n commands: [],\n };\n}\n\nexport function completeAuditEntry(\n entry: SkillExecution, \n success: boolean, \n error?: string\n): SkillExecution {\n const result: SkillExecution = {\n ...entry,\n completedAt: new Date().toISOString(),\n success,\n };\n if (error !== undefined) {\n result.error = error;\n }\n return result;\n}\n\nexport async function logSkillExecution(_execution: SkillExecution): Promise<void> {\n // Stub - no-op\n}\n\nexport async function getRecentAuditLogs(_limit: number = 10): Promise<AuditEntry[]> {\n return [];\n}\n\nexport async function getSkillAuditLogs(_skillName: string): Promise<AuditEntry[]> {\n return [];\n}\n"],"mappings":"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","names":["mkdir","writeFile","readFile","readdir","createHash","existsSync","join","mkdir","readFile","existsSync","join","existsSync","join","mkdir","join","existsSync","readFile","mkdir","join","existsSync","join","mkdir","existsSync","readdir","readFile","writeFile","createHash"]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-LT6VUZG2.js";
|
|
4
4
|
import {
|
|
5
5
|
searchIssues
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-62POBLFC.js";
|
|
7
7
|
|
|
8
8
|
// src/agent/goal-validator.ts
|
|
9
9
|
async function getActiveGoals(projectPath) {
|
|
@@ -38,9 +38,9 @@ async function recordGoalViolationFixed(goal, file, projectPath) {
|
|
|
38
38
|
lastFixedFile: file
|
|
39
39
|
}
|
|
40
40
|
});
|
|
41
|
-
const { resolveGoalViolation } = await import("./issue-store-
|
|
41
|
+
const { resolveGoalViolation } = await import("./issue-store-LZWZIGM7.js");
|
|
42
42
|
await resolveGoalViolation(file, goal.description, projectPath);
|
|
43
|
-
const { getGoalManager } = await import("./goal-manager-
|
|
43
|
+
const { getGoalManager } = await import("./goal-manager-ZBWKWEML.js");
|
|
44
44
|
const goalManager = getGoalManager(projectPath);
|
|
45
45
|
await goalManager.updateGoalProgress();
|
|
46
46
|
}
|
|
@@ -87,17 +87,15 @@ async function measureInitialGoalValue(description, projectPath) {
|
|
|
87
87
|
return 0;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
async function checkFilesForGoalViolations(goals, projectPath, filesToCheck, onProgress) {
|
|
91
|
-
const { isAIAvailable, runAIAnalysis } = await import("./client-
|
|
92
|
-
const { CodebaseIndex } = await import("./codebase-index-
|
|
90
|
+
async function checkFilesForGoalViolations(goals, projectPath, filesToCheck, onProgress, signal) {
|
|
91
|
+
const { isAIAvailable, runAIAnalysis } = await import("./client-INNE2GGZ.js");
|
|
92
|
+
const { CodebaseIndex } = await import("./codebase-index-5SEOESWM.js");
|
|
93
93
|
if (!isAIAvailable()) {
|
|
94
94
|
throw new Error("AI not available - ANTHROPIC_API_KEY not set");
|
|
95
95
|
}
|
|
96
96
|
const codebaseIndex = new CodebaseIndex(projectPath);
|
|
97
97
|
if (codebaseIndex.isEmpty()) {
|
|
98
98
|
onProgress?.("Building codebase index (first-time, may take a minute)...");
|
|
99
|
-
console.error("[Goal Check] Codebase index is empty - building index first...");
|
|
100
|
-
console.error("[Goal Check] This is a one-time operation. Future checks will be much faster.");
|
|
101
99
|
const { glob } = await import("glob");
|
|
102
100
|
const { stat } = await import("fs/promises");
|
|
103
101
|
const indexPattern = `${projectPath}/**/*.{ts,tsx,js,jsx,mjs,vue,svelte,astro,py,go,rs,java,c,cpp,h,hpp,cs,rb,php,css,scss,html}`;
|
|
@@ -118,6 +116,9 @@ async function checkFilesForGoalViolations(goals, projectPath, filesToCheck, onP
|
|
|
118
116
|
const toIndex = withStats.filter((f) => f !== null).sort((a, b) => b.mtime - a.mtime).slice(0, 500).map((f) => f.file);
|
|
119
117
|
let indexed = 0;
|
|
120
118
|
for (const filePath of toIndex) {
|
|
119
|
+
if (signal?.aborted) {
|
|
120
|
+
throw new DOMException("Scan cancelled", "AbortError");
|
|
121
|
+
}
|
|
121
122
|
let relativePath = filePath;
|
|
122
123
|
if (filePath.toLowerCase().startsWith(projectPath.toLowerCase() + "/")) {
|
|
123
124
|
relativePath = filePath.slice(projectPath.length + 1);
|
|
@@ -129,7 +130,6 @@ async function checkFilesForGoalViolations(goals, projectPath, filesToCheck, onP
|
|
|
129
130
|
}
|
|
130
131
|
}
|
|
131
132
|
await codebaseIndex.save();
|
|
132
|
-
console.error(`[Goal Check] Index built: ${indexed} files indexed`);
|
|
133
133
|
}
|
|
134
134
|
let files = [];
|
|
135
135
|
if (filesToCheck && filesToCheck.length > 0) {
|
|
@@ -202,7 +202,6 @@ async function checkFilesForGoalViolations(goals, projectPath, filesToCheck, onP
|
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
204
|
onProgress?.(`Checking ${filesToScan.length} files for violations...`);
|
|
205
|
-
console.error(`[Goal Check] ${files.length} files total, ${filesToScan.length} need scanning, ${files.length - filesToScan.length} using cache`);
|
|
206
205
|
const allViolations = [...cachedViolations];
|
|
207
206
|
if (filesToScan.length === 0) {
|
|
208
207
|
await codebaseIndex.save();
|
|
@@ -222,8 +221,8 @@ async function checkFilesForGoalViolations(goals, projectPath, filesToCheck, onP
|
|
|
222
221
|
const relativePath = filePath.replace(projectPath + "/", "");
|
|
223
222
|
return {
|
|
224
223
|
path: relativePath,
|
|
225
|
-
content
|
|
226
|
-
//
|
|
224
|
+
content
|
|
225
|
+
// Never truncate text in Trie Watch
|
|
227
226
|
};
|
|
228
227
|
} catch {
|
|
229
228
|
return null;
|
|
@@ -242,6 +241,7 @@ This is a MANUAL CHECK requested by the user. Report ALL goal violations you fin
|
|
|
242
241
|
For emoji detection, look for Unicode emoji characters.
|
|
243
242
|
`;
|
|
244
243
|
const result = await runAIAnalysis({
|
|
244
|
+
signal,
|
|
245
245
|
systemPrompt: `You are checking code for GOAL VIOLATIONS ONLY.
|
|
246
246
|
${goalsSection}
|
|
247
247
|
Reply ONLY with a JSON array. Each element must have:
|
|
@@ -351,4 +351,4 @@ export {
|
|
|
351
351
|
measureInitialGoalValue,
|
|
352
352
|
checkFilesForGoalViolations
|
|
353
353
|
};
|
|
354
|
-
//# sourceMappingURL=chunk-
|
|
354
|
+
//# sourceMappingURL=chunk-75ADWWUF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/agent/goal-validator.ts"],"sourcesContent":["/**\n * Goal Validator - Helpers for goal tracking\n * \n * Goal detection is handled entirely by the AI watcher in watch.ts.\n * The AI (Anthropic) checks every changed file against user-defined goals,\n * using the Trie's priority scoring for cost control.\n * \n * This module provides:\n * - getActiveGoals: loads active goals for the AI prompt\n * - recordGoalViolationCaught: tracks when a violation is detected\n * - recordGoalViolationFixed: tracks when a violation is auto-fixed\n * - measureInitialGoalValue: measures current state for new goals\n */\n\nimport type { Goal } from './project-state.js';\nimport { getProjectState } from './project-state.js';\nimport { searchIssues } from '../memory/issue-store.js';\n\n/**\n * Get active goals for a project (used by the AI watcher)\n */\nexport async function getActiveGoals(projectPath: string): Promise<Goal[]> {\n const projectState = getProjectState(projectPath);\n await projectState.load();\n return projectState.getAllGoals().filter(g => g.status === 'active');\n}\n\nexport async function recordGoalViolationCaught(\n goal: Goal,\n file: string,\n projectPath: string\n): Promise<void> {\n const projectState = getProjectState(projectPath);\n await projectState.load();\n \n const metadata = goal.metadata || {};\n const caughtCount = (metadata.caughtCount || 0) + 1;\n \n await projectState.updateGoal(goal.id, {\n metadata: {\n ...metadata,\n caughtCount,\n lastCaught: new Date().toISOString(),\n lastCaughtFile: file,\n },\n });\n}\n\nexport async function recordGoalViolationFixed(\n goal: Goal,\n file: string,\n projectPath: string\n): Promise<void> {\n const projectState = getProjectState(projectPath);\n await projectState.load();\n \n const metadata = goal.metadata || {};\n const fixedCount = (metadata.fixedCount || 0) + 1;\n \n await projectState.updateGoal(goal.id, {\n metadata: {\n ...metadata,\n fixedCount,\n lastFixed: new Date().toISOString(),\n lastFixedFile: file,\n },\n });\n \n // Resolve the goal-violation issue in the issue store\n // This is the source of truth - measureGoalMetric() will query from here\n const { resolveGoalViolation } = await import('../memory/issue-store.js');\n await resolveGoalViolation(file, goal.description, projectPath);\n \n // Trigger immediate progress update so UI reflects the fix\n const { getGoalManager } = await import('./goal-manager.js');\n const goalManager = getGoalManager(projectPath);\n await goalManager.updateGoalProgress();\n}\n\n/**\n * Measure the initial value for a new goal based on existing issues.\n * This sets a proper baseline so progress calculation works correctly.\n * \n * For reduction goals (like \"no emojis\"), we count current violations.\n * For other goals, we use semantic matching against existing issues.\n * \n * Returns the count to use as both startValue and currentValue.\n */\nexport async function measureInitialGoalValue(\n description: string,\n projectPath: string\n): Promise<number> {\n try {\n const issues = await searchIssues('', {\n workDir: projectPath,\n limit: 1000,\n includeResolved: false,\n });\n \n if (issues.length === 0) {\n return 0;\n }\n \n const desc = description.toLowerCase();\n \n // Check for goal-violation issues that might already exist for similar goals\n const goalViolations = issues.filter(r => \n r.issue.agent === 'goal-violation' &&\n r.issue.issue.toLowerCase().includes(desc.slice(0, 30))\n );\n if (goalViolations.length > 0) {\n return goalViolations.length;\n }\n \n // Security goals\n if (desc.includes('security') || desc.includes('vulnerab')) {\n return issues.filter(r => \n r.issue.agent === 'security' || r.issue.severity === 'critical'\n ).length;\n }\n \n // Type safety goals\n if (desc.includes('type') || desc.includes('typescript') || desc.includes('any type')) {\n return issues.filter(r => \n r.issue.agent === 'typecheck' ||\n r.issue.issue.toLowerCase().includes('type')\n ).length;\n }\n \n // Bug-related goals\n if (desc.includes('bug') || desc.includes('error')) {\n return issues.filter(r => \n r.issue.agent === 'bug-finding' ||\n r.issue.severity === 'critical' ||\n r.issue.severity === 'serious'\n ).length;\n }\n \n // Dead code / unused code goals\n if (desc.includes('dead code') || desc.includes('unused')) {\n return issues.filter(r => {\n const msg = r.issue.issue.toLowerCase();\n return msg.includes('unused') || msg.includes('dead code') || msg.includes('never used');\n }).length;\n }\n \n // For custom goals like \"no emojis\", we start at 0 and let the AI scanner find violations\n // This is correct because we don't know the count until a scan runs\n return 0;\n } catch {\n return 0;\n }\n}\n\n/**\n * Manually check files against goals\n * Returns violations found\n * \n * NOW WITH CACHING: Uses CodebaseIndex to avoid re-scanning unchanged files\n */\nexport async function checkFilesForGoalViolations(\n goals: Goal[],\n projectPath: string,\n filesToCheck?: string[],\n onProgress?: (message: string) => void,\n signal?: AbortSignal\n): Promise<Array<{ file: string; message: string; severity: 'critical' | 'warning' | 'info' }>> {\n // Import AI client and codebase index\n const { isAIAvailable, runAIAnalysis } = await import('../ai/client.js');\n const { CodebaseIndex } = await import('../context/codebase-index.js');\n \n if (!isAIAvailable()) {\n throw new Error('AI not available - ANTHROPIC_API_KEY not set');\n }\n \n // Initialize codebase index for caching\n const codebaseIndex = new CodebaseIndex(projectPath);\n \n // Check if index needs to be built\n if (codebaseIndex.isEmpty()) {\n onProgress?.('Building codebase index (first-time, may take a minute)...');\n \n // Auto-index using same file selection as checks (most recently modified) so cache overlaps\n const { glob } = await import('glob');\n const { stat } = await import('fs/promises');\n const indexPattern = `${projectPath}/**/*.{ts,tsx,js,jsx,mjs,vue,svelte,astro,py,go,rs,java,c,cpp,h,hpp,cs,rb,php,css,scss,html}`;\n const indexFiles = await glob(indexPattern, {\n ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**', '**/.trie/**', '**/coverage/**'],\n nodir: true,\n });\n \n const withStats = await Promise.all(\n indexFiles.map(async (f) => {\n try {\n const stats = await stat(f);\n return { file: f, mtime: stats.mtime.getTime() };\n } catch {\n return null;\n }\n })\n );\n const toIndex = withStats\n .filter((f): f is { file: string; mtime: number } => f !== null)\n .sort((a, b) => b.mtime - a.mtime)\n .slice(0, 500)\n .map((f) => f.file);\n \n let indexed = 0;\n for (const filePath of toIndex) {\n if (signal?.aborted) {\n throw new DOMException('Scan cancelled', 'AbortError');\n }\n let relativePath = filePath;\n if (filePath.toLowerCase().startsWith(projectPath.toLowerCase() + '/')) {\n relativePath = filePath.slice(projectPath.length + 1);\n }\n const result = await codebaseIndex.indexFile(relativePath);\n if (result) indexed++;\n if (indexed % 50 === 0) {\n onProgress?.(`Indexing files (${indexed}/${toIndex.length})...`);\n }\n }\n \n await codebaseIndex.save();\n }\n \n // Get files to check\n let files: string[] = [];\n if (filesToCheck && filesToCheck.length > 0) {\n files = filesToCheck;\n } else {\n // MANUAL CHECK MODE: Scan ALL relevant files, not just recently modified\n const { glob } = await import('glob');\n \n const pattern = `${projectPath}/**/*.{ts,tsx,js,jsx,py,go,rs,java,c,cpp,h,hpp,cs,rb,php,css,scss,html,vue,svelte}`;\n const allFiles = await glob(pattern, {\n ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.git/**', '**/.trie/**', '**/coverage/**'],\n nodir: true,\n });\n \n // For manual checks, use more files but still reasonable limit\n // Sort by modification time to prioritize recently modified\n const { stat } = await import('fs/promises');\n const withStats = await Promise.all(\n allFiles.map(async (f) => {\n try {\n const stats = await stat(f);\n return { file: f, mtime: stats.mtime.getTime() };\n } catch {\n return null;\n }\n })\n );\n \n files = withStats\n .filter((f): f is { file: string; mtime: number } => f !== null)\n .sort((a, b) => b.mtime - a.mtime)\n .slice(0, 100) // Check up to 100 files for manual scans\n .map(f => f.file);\n }\n \n if (files.length === 0) {\n throw new Error('No files found to check');\n }\n\n // Pre-index the files we're about to check so cache lookups work.\n // The initial index may have indexed different files (first 500 from glob), while we check\n // the 100 most recently modified - these can have zero overlap, causing every run to scan.\n for (const filePath of files) {\n let rel = filePath;\n if (filePath.toLowerCase().startsWith(projectPath.toLowerCase() + '/')) {\n rel = filePath.slice(projectPath.length + 1);\n } else if (filePath.startsWith('/') && !filePath.toLowerCase().startsWith(projectPath.toLowerCase())) {\n continue;\n }\n await codebaseIndex.indexFile(rel);\n }\n \n // Check which files need scanning vs can use cached results\n const filesToScan: string[] = [];\n const cachedViolations: Array<{ file: string; message: string; severity: 'critical' | 'warning' | 'info' }> = [];\n \n for (const filePath of files) {\n // Handle case-insensitive filesystems (macOS) and ensure we get a proper relative path\n let relativePath = filePath;\n if (filePath.toLowerCase().startsWith(projectPath.toLowerCase() + '/')) {\n relativePath = filePath.slice(projectPath.length + 1);\n } else if (filePath.startsWith('/')) {\n // Already absolute but doesn't match projectPath - skip this file\n // This can happen with stale cache entries from different projects\n continue;\n }\n const hasChanged = await codebaseIndex.hasChanged(relativePath);\n \n if (hasChanged) {\n // File changed or not indexed - needs scanning\n // Try to index the file first; skip if it doesn't exist\n const indexed = await codebaseIndex.indexFile(relativePath);\n if (indexed) {\n filesToScan.push(filePath);\n }\n // If indexFile returns null, file doesn't exist - skip it silently\n } else {\n // File unchanged - check cache for each goal\n for (const goal of goals) {\n const cached = codebaseIndex.getCachedViolations(relativePath, goal.id);\n if (cached && cached.length > 0) {\n const violation = cached[0];\n if (violation && violation.found) {\n cachedViolations.push({\n file: relativePath,\n message: `Goal \"${goal.description}\" violated in ${relativePath}: ${violation.details || 'Violation found'} [${violation.confidence || 90}% confidence] (cached)`,\n severity: 'warning',\n });\n }\n } else {\n // No cache for this goal - needs scanning\n if (!filesToScan.includes(filePath)) {\n filesToScan.push(filePath);\n }\n }\n }\n }\n }\n \n onProgress?.(`Checking ${filesToScan.length} files for violations...`);\n \n // Process files that need scanning in batches\n const allViolations: Array<{ file: string; message: string; severity: 'critical' | 'warning' | 'info' }> = [...cachedViolations];\n \n if (filesToScan.length === 0) {\n // All results from cache!\n await codebaseIndex.save();\n return allViolations;\n }\n \n // For large file sets, process in batches to avoid token limits\n const BATCH_SIZE = 25; // Process 25 files at a time\n \n const totalBatches = Math.ceil(filesToScan.length / BATCH_SIZE);\n for (let batchStart = 0; batchStart < filesToScan.length; batchStart += BATCH_SIZE) {\n const batchNum = Math.floor(batchStart / BATCH_SIZE) + 1;\n onProgress?.(`Analyzing files (batch ${batchNum}/${totalBatches})...`);\n const batchFiles = filesToScan.slice(batchStart, batchStart + BATCH_SIZE);\n \n // Read file contents for this batch\n const { readFile } = await import('fs/promises');\n const fileContents = await Promise.all(\n batchFiles.map(async (filePath) => {\n try {\n const content = await readFile(filePath, 'utf-8');\n const relativePath = filePath.replace(projectPath + '/', '');\n return {\n path: relativePath,\n content: content, // Never truncate text in Trie Watch\n };\n } catch {\n return null;\n }\n })\n );\n \n const validFiles = fileContents.filter((f): f is { path: string; content: string } => f !== null);\n \n if (validFiles.length === 0) continue;\n \n // Build files block for AI\n const filesBlock = validFiles\n .map(f => `--- ${f.path} ---\\n${f.content}`)\n .join('\\n\\n');\n \n // Build goals section\n const goalsSection = `\nUSER-DEFINED GOALS (check EVERY file against ALL goals):\n${goals.map((g, i) => ` ${i + 1}. \"${g.description}\"`).join('\\n')}\n\nThis is a MANUAL CHECK requested by the user. Report ALL goal violations you find.\nFor emoji detection, look for Unicode emoji characters.\n`;\n \n // Run AI analysis\n const result = await runAIAnalysis({\n signal,\n systemPrompt: `You are checking code for GOAL VIOLATIONS ONLY.\n${goalsSection}\nReply ONLY with a JSON array. Each element must have:\n- \"file\": relative file path\n- \"severity\": \"critical\" | \"major\" | \"minor\"\n- \"description\": 1-sentence description of the goal violation with specific examples\n- \"confidence\": number 0-100, how confident you are this is a violation\n- \"isGoalViolation\": true (always true for this scan)\n- \"goalIndex\": 0-based index of the violated goal\n\nCRITICAL DETECTION RULES:\n\n**EMOJIS**: Any Unicode emoji characters including but not limited to:\n- Emoticons: 😀😃😄😊🙂🙃😉😇🥰😍🤩😘😗☺️😚😙🥲\n- Symbols: ⚡️⚠️✅❌➜→←↑↓►◄▲▼★☆●○◆◇■□▪️▫️\n- Objects: 📊📈📉💻🖥️📱⌨️🖱️💾💿📀🔧🔨⚙️🛠️\n- Actions: 🔥💪👍👎👏🙌🤝✊👊🎯🎉🎊🚀\n- Weather: ☀️🌤️⛅☁️🌦️🌧️⛈️🌩️🌨️❄️\n- ALL OTHER Unicode emoji in ranges U+1F300-U+1F9FF, U+2600-U+27BF, U+2B00-U+2BFF\n\n**COLORS**: For \"purple\" or \"gradient\" goals, check:\n- CSS: purple, #purple, hsl(purple), rgb(purple), violet, #8B00FF, #9B59D6, etc.\n- Gradients: linear-gradient, radial-gradient, conic-gradient, background-image with gradients\n- Tailwind: purple-*, violet-*, bg-gradient-*\n- Styled components or CSS-in-JS with purple/violet/gradient\n\nBe EXTREMELY thorough. Check:\n1. String literals and template literals\n2. JSX/HTML content\n3. CSS files and style blocks\n4. Comments (emojis in comments still violate \"no emojis\")\n5. console.log statements\n6. Component names, variable names (if they contain emojis)\n\nIf a goal says \"no emojis\" and you see ANY emoji ANYWHERE in the file, report it.\nIf a goal says \"no console.log\" and you see console.log ANYWHERE, report it.\nIf a goal says \"no purple/gradient\" and you see ANY purple color or gradient, report it.\n\nIf no violations found, reply with: []\nOutput ONLY the JSON array, no markdown fences, no commentary.`,\n userPrompt: `Check these ${validFiles.length} files for goal violations:\\n\\n${filesBlock}`,\n maxTokens: 8192, // Increased for larger codebases\n temperature: 0.1,\n });\n \n // Parse response\n let issues: Array<{\n file: string;\n severity: 'critical' | 'major' | 'minor';\n description: string;\n confidence: number;\n isGoalViolation: boolean;\n goalIndex?: number;\n }> = [];\n \n try {\n const cleaned = result.content.replace(/```json?\\n?|\\n?```/g, '').trim();\n issues = JSON.parse(cleaned);\n if (!Array.isArray(issues)) issues = [];\n } catch (err) {\n // Parse failed - continue to next batch\n console.debug('[Goal Check] Batch parse failed:', err);\n continue;\n }\n \n // Convert to violation format and record\n for (const issue of issues) {\n if (!issue.isGoalViolation || issue.confidence < 50) continue;\n if (issue.goalIndex == null || issue.goalIndex < 0 || issue.goalIndex >= goals.length) continue;\n \n const goal = goals[issue.goalIndex];\n if (!goal) continue; // Defensive check\n const severity = issue.severity === 'critical' ? 'critical' : 'warning';\n const message = `Goal \"${goal.description}\" violated in ${issue.file}: ${issue.description} [${issue.confidence}% confidence]`;\n \n allViolations.push({\n file: issue.file,\n message,\n severity,\n });\n \n // Cache the result in codebase index\n codebaseIndex.recordViolation(\n issue.file,\n goal.id,\n goal.description,\n true, // found\n issue.description,\n issue.confidence\n );\n \n // Record violation\n await recordGoalViolationCaught(goal, issue.file, projectPath);\n }\n \n // Also record \"no violation\" for scanned files\n for (const file of validFiles) {\n for (let goalIdx = 0; goalIdx < goals.length; goalIdx++) {\n const goal = goals[goalIdx];\n if (!goal) continue;\n const hasViolation = issues.some(i => i.file === file.path && i.goalIndex === goalIdx);\n if (!hasViolation) {\n codebaseIndex.recordViolation(\n file.path,\n goal.id,\n goal.description,\n false, // not found\n undefined,\n 100\n );\n }\n }\n }\n }\n \n // Save updated index\n await codebaseIndex.save();\n \n return allViolations;\n}\n"],"mappings":"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","names":[]}
|