@triedotdev/mcp 1.0.166 → 1.0.167
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 +337 -801
- package/dist/chunk-2HF65EHQ.js +311 -0
- package/dist/chunk-2HF65EHQ.js.map +1 -0
- package/dist/{chunk-JNUOW2JS.js → chunk-4MXH2ZPT.js} +12 -12
- package/dist/chunk-4MXH2ZPT.js.map +1 -0
- package/dist/{chunk-LR5M4RTN.js → chunk-575YT2SD.js} +1 -1
- package/dist/chunk-575YT2SD.js.map +1 -0
- package/dist/{chunk-ZKKKLRZZ.js → chunk-5BRRRTN6.js} +4 -4
- package/dist/{chunk-TQOO6A4G.js → chunk-7WITSO22.js} +3 -3
- package/dist/{chunk-ACU2RJUJ.js → chunk-F6WFNUAY.js} +2 -2
- package/dist/{chunk-VR4VWXXU.js → chunk-G2TGF6TR.js} +9 -2
- package/dist/chunk-G2TGF6TR.js.map +1 -0
- package/dist/{chunk-ZBXW244P.js → chunk-HVCDY3AK.js} +3 -3
- package/dist/chunk-HVCDY3AK.js.map +1 -0
- package/dist/{chunk-HOGKPDZA.js → chunk-LQIMKE3P.js} +678 -151
- package/dist/chunk-LQIMKE3P.js.map +1 -0
- package/dist/{chunk-2Z3TQNNK.js → chunk-MRHKX5M5.js} +3 -3
- package/dist/{chunk-OLNZJ3XV.js → chunk-Q63FFI6D.js} +2 -2
- package/dist/{chunk-S36IO3EE.js → chunk-XE6KQRKZ.js} +9 -8
- package/dist/chunk-XE6KQRKZ.js.map +1 -0
- package/dist/{chunk-GDWA3CH3.js → chunk-XPZZFPBZ.js} +30 -6
- package/dist/chunk-XPZZFPBZ.js.map +1 -0
- package/dist/{chunk-JEZ7XJQN.js → chunk-XTFWT2XM.js} +2 -2
- package/dist/{chunk-UXRW2YSP.js → chunk-YDHUCDHM.js} +18 -112
- package/dist/chunk-YDHUCDHM.js.map +1 -0
- package/dist/{chunk-LG5CBK6A.js → chunk-YZ6Y2H3P.js} +21 -196
- package/dist/chunk-YZ6Y2H3P.js.map +1 -0
- package/dist/{chunk-MVVPJ73K.js → chunk-ZJF5FTBX.js} +126 -358
- package/dist/chunk-ZJF5FTBX.js.map +1 -0
- package/dist/cli/create-agent.js +1 -1
- package/dist/cli/create-agent.js.map +1 -1
- package/dist/cli/main.js +194 -849
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/yolo-daemon.js +15 -14
- package/dist/cli/yolo-daemon.js.map +1 -1
- package/dist/{fast-analyzer-NJQO3TFD.js → fast-analyzer-XXYMOXRK.js} +3 -3
- package/dist/git-EO5SRFMN.js +28 -0
- package/dist/{github-ingester-TFBDUDIY.js → github-ingester-ZOKK6GRS.js} +3 -3
- package/dist/{goal-manager-DVX24UPZ.js → goal-manager-YOB7VWK7.js} +5 -4
- package/dist/{goal-validator-6Y5CDEMJ.js → goal-validator-ULKIBDPX.js} +5 -4
- package/dist/{hypothesis-UKPGOYY2.js → hypothesis-7BFFT5JY.js} +5 -4
- package/dist/index.js +19 -18
- package/dist/index.js.map +1 -1
- package/dist/{issue-store-UZAPI5DU.js → issue-store-ZIRP23EP.js} +4 -3
- package/dist/{ledger-CNFCJKHX.js → ledger-TWZTGDFA.js} +3 -2
- package/dist/{linear-ingester-PLES2BRS.js → linear-ingester-XXPAZZRW.js} +3 -3
- package/dist/{output-manager-JNMEAXFO.js → output-manager-RVJ37XKA.js} +2 -2
- package/dist/server/mcp-server.js +19 -18
- package/dist/{tiered-storage-OP74NPJY.js → tiered-storage-Z3YCR465.js} +2 -2
- package/dist/{trie-agent-6SWUHCVO.js → trie-agent-3YDPEGHJ.js} +9 -8
- package/dist/trie-agent-3YDPEGHJ.js.map +1 -0
- package/package.json +3 -2
- package/dist/chunk-GDWA3CH3.js.map +0 -1
- package/dist/chunk-HOGKPDZA.js.map +0 -1
- package/dist/chunk-JNUOW2JS.js.map +0 -1
- package/dist/chunk-LG5CBK6A.js.map +0 -1
- package/dist/chunk-LR5M4RTN.js.map +0 -1
- package/dist/chunk-MVVPJ73K.js.map +0 -1
- package/dist/chunk-S36IO3EE.js.map +0 -1
- package/dist/chunk-UXRW2YSP.js.map +0 -1
- package/dist/chunk-VR4VWXXU.js.map +0 -1
- package/dist/chunk-ZBXW244P.js.map +0 -1
- /package/dist/{chunk-ZKKKLRZZ.js.map → chunk-5BRRRTN6.js.map} +0 -0
- /package/dist/{chunk-TQOO6A4G.js.map → chunk-7WITSO22.js.map} +0 -0
- /package/dist/{chunk-ACU2RJUJ.js.map → chunk-F6WFNUAY.js.map} +0 -0
- /package/dist/{chunk-2Z3TQNNK.js.map → chunk-MRHKX5M5.js.map} +0 -0
- /package/dist/{chunk-OLNZJ3XV.js.map → chunk-Q63FFI6D.js.map} +0 -0
- /package/dist/{chunk-JEZ7XJQN.js.map → chunk-XTFWT2XM.js.map} +0 -0
- /package/dist/{fast-analyzer-NJQO3TFD.js.map → fast-analyzer-XXYMOXRK.js.map} +0 -0
- /package/dist/{github-ingester-TFBDUDIY.js.map → git-EO5SRFMN.js.map} +0 -0
- /package/dist/{goal-manager-DVX24UPZ.js.map → github-ingester-ZOKK6GRS.js.map} +0 -0
- /package/dist/{goal-validator-6Y5CDEMJ.js.map → goal-manager-YOB7VWK7.js.map} +0 -0
- /package/dist/{hypothesis-UKPGOYY2.js.map → goal-validator-ULKIBDPX.js.map} +0 -0
- /package/dist/{issue-store-UZAPI5DU.js.map → hypothesis-7BFFT5JY.js.map} +0 -0
- /package/dist/{ledger-CNFCJKHX.js.map → issue-store-ZIRP23EP.js.map} +0 -0
- /package/dist/{linear-ingester-PLES2BRS.js.map → ledger-TWZTGDFA.js.map} +0 -0
- /package/dist/{output-manager-JNMEAXFO.js.map → linear-ingester-XXPAZZRW.js.map} +0 -0
- /package/dist/{tiered-storage-OP74NPJY.js.map → output-manager-RVJ37XKA.js.map} +0 -0
- /package/dist/{trie-agent-6SWUHCVO.js.map → tiered-storage-Z3YCR465.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/storage/tiered-storage.ts"],"sourcesContent":["/**\n * Tiered Storage System\n * \n * Three-tier architecture for context management:\n * - HOT: In-memory, current session data\n * - WARM: SQLite DB, queryable governance/facts/blockers\n * - COLD: Full history, indexed but not actively queried\n * \n * This prevents context pollution by keeping agents focused on\n * relevant signal rather than dumping everything into context.\n */\n\nimport { writeFile, mkdir } from 'fs/promises';\nimport { join } from 'path';\nimport { createHash } from 'node:crypto';\nimport Database, { type Database as DatabaseType } from 'better-sqlite3';\nimport type {\n Governance,\n Blocker,\n ExtractedSignal,\n ContextQuery,\n Nudge,\n Gotcha,\n} from '../types/signal.js';\nimport { getTrieDirectory } from '../utils/workspace.js';\n\nexport class TieredStorage {\n private workDir: string;\n private hotCache: Map<string, any> = new Map();\n private warmDb: DatabaseType | null = null;\n\n constructor(workDir: string) {\n this.workDir = workDir;\n }\n\n /**\n * Initialize storage directories and database\n */\n async initialize(): Promise<void> {\n const trieDir = getTrieDirectory(this.workDir);\n \n // Create directories\n await mkdir(join(trieDir, 'hot'), { recursive: true });\n await mkdir(join(trieDir, 'warm'), { recursive: true });\n await mkdir(join(trieDir, 'cold'), { recursive: true });\n\n // Initialize warm database\n const dbPath = join(trieDir, 'warm', 'governance.db');\n this.warmDb = new Database(dbPath);\n \n // Create tables\n this.warmDb.exec(`\n CREATE TABLE IF NOT EXISTS governance (\n id TEXT PRIMARY KEY,\n decision TEXT NOT NULL,\n context TEXT NOT NULL,\n reasoning TEXT,\n timestamp TEXT NOT NULL,\n who TEXT,\n files TEXT NOT NULL, -- JSON array\n tags TEXT NOT NULL, -- JSON array\n expandedTags TEXT, -- JSON array (with synonyms)\n relatedTo TEXT, -- JSON array\n tradeoffs TEXT, -- JSON array\n status TEXT NOT NULL,\n supersededBy TEXT,\n hash TEXT, -- SHA-256 fingerprint (first 16 hex chars)\n dependencies TEXT, -- JSON array (npm packages, services)\n codebaseArea TEXT, -- JSON array (frontend, backend, auth, etc.)\n domain TEXT, -- JSON array (payments, compliance, etc.)\n lastAccessed TEXT NOT NULL,\n accessCount INTEGER DEFAULT 0\n );\n\n CREATE TABLE IF NOT EXISTS facts (\n id TEXT PRIMARY KEY,\n fact TEXT NOT NULL,\n source TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n tags TEXT NOT NULL, -- JSON array\n expandedTags TEXT, -- JSON array (with synonyms)\n relatedGovernance TEXT, -- JSON array\n confidence REAL NOT NULL,\n lastAccessed TEXT NOT NULL,\n accessCount INTEGER DEFAULT 0\n );\n\n CREATE TABLE IF NOT EXISTS blockers (\n id TEXT PRIMARY KEY,\n blocker TEXT NOT NULL,\n impact TEXT NOT NULL,\n affectedAreas TEXT NOT NULL, -- JSON array\n timestamp TEXT NOT NULL,\n resolvedAt TEXT,\n resolution TEXT,\n tags TEXT NOT NULL, -- JSON array\n expandedTags TEXT, -- JSON array (with synonyms)\n lastAccessed TEXT NOT NULL,\n accessCount INTEGER DEFAULT 0\n );\n\n CREATE TABLE IF NOT EXISTS questions (\n id TEXT PRIMARY KEY,\n question TEXT NOT NULL,\n context TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n answeredAt TEXT,\n answer TEXT,\n relatedGovernance TEXT, -- JSON array\n tags TEXT NOT NULL, -- JSON array\n expandedTags TEXT, -- JSON array (with synonyms)\n lastAccessed TEXT NOT NULL,\n accessCount INTEGER DEFAULT 0\n );\n\n CREATE TABLE IF NOT EXISTS nudges (\n id TEXT PRIMARY KEY,\n message TEXT NOT NULL,\n severity TEXT NOT NULL, -- 'critical', 'high', 'warning', 'info'\n file TEXT,\n category TEXT, -- 'quality', 'security', 'performance', etc.\n goalId TEXT, -- Related goal ID if this is a goal violation\n timestamp TEXT NOT NULL,\n resolved BOOLEAN NOT NULL DEFAULT 0,\n resolvedAt TEXT,\n resolution TEXT, -- How it was resolved: 'dismissed', 'fixed', 'auto-fixed'\n dismissed BOOLEAN NOT NULL DEFAULT 0,\n priority INTEGER DEFAULT 5, -- 1-10 priority score\n suggestedAction TEXT,\n relatedIssues TEXT, -- JSON array\n metadata TEXT -- JSON object for additional data\n );\n\n CREATE TABLE IF NOT EXISTS gotchas (\n id TEXT PRIMARY KEY,\n message TEXT NOT NULL,\n confidence REAL NOT NULL, -- 0-1 confidence score\n riskLevel TEXT NOT NULL, -- 'low', 'medium', 'high', 'critical'\n recommendation TEXT NOT NULL,\n file TEXT,\n timestamp TEXT NOT NULL,\n precedentId TEXT, -- ID of related historical incident/governance record\n tags TEXT NOT NULL, -- JSON array\n evidence TEXT NOT NULL, -- JSON object with pastIncidents, matchingPatterns, relatedTickets\n resolved BOOLEAN NOT NULL DEFAULT 0,\n resolvedAt TEXT,\n resolution TEXT -- 'confirmed', 'false-positive', 'dismissed'\n );\n\n CREATE INDEX IF NOT EXISTS idx_governance_tags ON governance(tags);\n CREATE INDEX IF NOT EXISTS idx_governance_expanded ON governance(expandedTags);\n CREATE INDEX IF NOT EXISTS idx_governance_timestamp ON governance(timestamp);\n CREATE INDEX IF NOT EXISTS idx_governance_status ON governance(status);\n CREATE INDEX IF NOT EXISTS idx_governance_area ON governance(codebaseArea);\n CREATE INDEX IF NOT EXISTS idx_governance_domain ON governance(domain);\n CREATE INDEX IF NOT EXISTS idx_facts_tags ON facts(tags);\n CREATE INDEX IF NOT EXISTS idx_facts_expanded ON facts(expandedTags);\n CREATE INDEX IF NOT EXISTS idx_blockers_impact ON blockers(impact);\n CREATE INDEX IF NOT EXISTS idx_blockers_resolved ON blockers(resolvedAt);\n CREATE INDEX IF NOT EXISTS idx_nudges_timestamp ON nudges(timestamp);\n CREATE INDEX IF NOT EXISTS idx_nudges_resolved ON nudges(resolved);\n CREATE INDEX IF NOT EXISTS idx_nudges_severity ON nudges(severity);\n CREATE INDEX IF NOT EXISTS idx_nudges_file ON nudges(file);\n CREATE INDEX IF NOT EXISTS idx_gotchas_timestamp ON gotchas(timestamp);\n CREATE INDEX IF NOT EXISTS idx_gotchas_resolved ON gotchas(resolved);\n CREATE INDEX IF NOT EXISTS idx_gotchas_riskLevel ON gotchas(riskLevel);\n CREATE INDEX IF NOT EXISTS idx_gotchas_file ON gotchas(file);\n CREATE INDEX IF NOT EXISTS idx_gotchas_tags ON gotchas(tags);\n `);\n }\n\n /**\n * Store extracted signal with enriched metadata in warm storage\n */\n async storeSignal(signal: ExtractedSignal, metadata?: {\n expandedTags?: string[];\n dependencies?: string[];\n codebaseArea?: string[];\n domain?: string[];\n }): Promise<void> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const now = new Date().toISOString();\n \n // Log what we're storing for debugging\n const totalSignals = signal.governance.length + signal.facts.length + \n signal.blockers.length + signal.questions.length;\n if (totalSignals > 0) {\n console.debug(`[Storage] Storing ${totalSignals} signals: ${signal.governance.length}g, ${signal.facts.length}f, ${signal.blockers.length}b, ${signal.questions.length}q`);\n }\n\n // Store governance records\n const governanceStmt = this.warmDb.prepare(`\n INSERT OR REPLACE INTO governance \n (id, decision, context, reasoning, timestamp, who, files, tags, expandedTags, relatedTo, tradeoffs, status, supersededBy, hash, dependencies, codebaseArea, domain, lastAccessed, accessCount)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)\n `);\n\n const governanceRecords = signal.governance;\n for (const gov of governanceRecords) {\n const hash = gov.hash || createHash('sha256')\n .update(`${gov.decision}|${gov.context}|${gov.when}`)\n .digest('hex')\n .slice(0, 16);\n governanceStmt.run(\n gov.id,\n gov.decision,\n gov.context,\n gov.reasoning || null,\n gov.when,\n gov.who || null,\n JSON.stringify(gov.files),\n JSON.stringify(gov.tags),\n JSON.stringify(metadata?.expandedTags || []),\n JSON.stringify(gov.relatedTo || []),\n JSON.stringify(gov.tradeoffs || []),\n gov.status,\n gov.supersededBy || null,\n hash,\n JSON.stringify(metadata?.dependencies || []),\n JSON.stringify(metadata?.codebaseArea || []),\n JSON.stringify(metadata?.domain || []),\n now\n );\n }\n\n // Store facts\n const factStmt = this.warmDb.prepare(`\n INSERT OR REPLACE INTO facts\n (id, fact, source, timestamp, tags, expandedTags, relatedGovernance, confidence, lastAccessed, accessCount)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0)\n `);\n\n for (const fact of signal.facts) {\n factStmt.run(\n fact.id,\n fact.fact,\n fact.source,\n fact.when,\n JSON.stringify(fact.tags),\n JSON.stringify(metadata?.expandedTags || []),\n JSON.stringify(fact.relatedGovernance || []),\n fact.confidence,\n now\n );\n }\n\n // Store blockers\n const blockerStmt = this.warmDb.prepare(`\n INSERT OR REPLACE INTO blockers\n (id, blocker, impact, affectedAreas, timestamp, resolvedAt, resolution, tags, expandedTags, lastAccessed, accessCount)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)\n `);\n\n for (const blocker of signal.blockers) {\n blockerStmt.run(\n blocker.id,\n blocker.blocker,\n blocker.impact,\n JSON.stringify(blocker.affectedAreas),\n blocker.when,\n blocker.resolvedAt || null,\n blocker.resolution || null,\n JSON.stringify(blocker.tags),\n JSON.stringify(metadata?.expandedTags || []),\n now\n );\n }\n\n // Store questions\n const questionStmt = this.warmDb.prepare(`\n INSERT OR REPLACE INTO questions\n (id, question, context, timestamp, answeredAt, answer, relatedGovernance, tags, expandedTags, lastAccessed, accessCount)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 0)\n `);\n\n for (const q of signal.questions) {\n questionStmt.run(\n q.id,\n q.question,\n q.context,\n q.when,\n q.answeredAt || null,\n q.answer || null,\n JSON.stringify(q.relatedGovernance || []),\n JSON.stringify(q.tags),\n JSON.stringify(metadata?.expandedTags || []),\n now\n );\n }\n\n // Store gotchas if present\n if (signal.gotchas && signal.gotchas.length > 0) {\n const gotchaStmt = this.warmDb.prepare(`\n INSERT OR REPLACE INTO gotchas\n (id, message, confidence, riskLevel, recommendation, file, timestamp, precedentId, tags, evidence, resolved, resolvedAt, resolution)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n for (const g of signal.gotchas) {\n gotchaStmt.run(\n g.id,\n g.message,\n g.confidence,\n g.riskLevel,\n g.recommendation,\n g.file || null,\n g.timestamp,\n g.precedentId || null,\n JSON.stringify(g.tags || []),\n JSON.stringify(g.evidence || { pastIncidents: [], matchingPatterns: [], relatedTickets: [] }),\n g.resolved ? 1 : 0,\n g.resolvedAt || null,\n g.resolution || null\n );\n }\n }\n \n // Log successful storage\n const storedCount = signal.governance.length + signal.facts.length + \n signal.blockers.length + signal.questions.length +\n (signal.gotchas?.length || 0);\n if (storedCount > 0) {\n console.debug(`[Storage] ✓ Successfully stored ${storedCount} signals to governance.db`);\n }\n }\n\n /**\n * Query governance records from warm storage with expanded tag matching\n */\n async queryGovernance(query: ContextQuery): Promise<Governance[]> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n let sql = 'SELECT * FROM governance WHERE status = ?';\n const params: any[] = ['active'];\n\n // Add filters - search both tags and expandedTags for broader matching\n if (query.tags && query.tags.length > 0) {\n sql += ' AND (' + query.tags.map(() => '(tags LIKE ? OR expandedTags LIKE ?)').join(' OR ') + ')';\n for (const tag of query.tags) {\n params.push(`%\"${tag}\"%`, `%\"${tag}\"%`);\n }\n }\n\n // Filter by codebase area if specified\n if (query.filters?.codebaseArea) {\n sql += ' AND codebaseArea LIKE ?';\n params.push(`%\"${query.filters.codebaseArea}\"%`);\n }\n\n // Filter by domain if specified\n if (query.filters?.domain) {\n sql += ' AND domain LIKE ?';\n params.push(`%\"${query.filters.domain}\"%`);\n }\n\n if (query.timeWindow) {\n if (query.timeWindow.start) {\n sql += ' AND timestamp >= ?';\n params.push(query.timeWindow.start);\n }\n if (query.timeWindow.end) {\n sql += ' AND timestamp <= ?';\n params.push(query.timeWindow.end);\n }\n }\n\n sql += ' ORDER BY timestamp DESC';\n\n if (query.limit) {\n sql += ' LIMIT ?';\n params.push(query.limit);\n }\n\n const rows = this.warmDb.prepare(sql).all(...params) as any[];\n\n return rows.map(row => ({\n id: row.id,\n decision: row.decision,\n context: row.context,\n reasoning: row.reasoning,\n when: row.timestamp || row.when,\n who: row.who,\n files: JSON.parse(row.files),\n tags: JSON.parse(row.tags),\n relatedTo: JSON.parse(row.relatedTo || '[]'),\n tradeoffs: JSON.parse(row.tradeoffs || '[]'),\n status: row.status,\n supersededBy: row.supersededBy,\n hash: row.hash || undefined,\n }));\n }\n\n /**\n * Query facts from warm storage (for Learned Signals display)\n */\n async queryFacts(query: { limit?: number } = {}): Promise<Array<{ id: string; fact: string; source: string; when: string; tags: string[]; confidence: number }>> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const limit = query.limit ?? 20;\n const rows = this.warmDb.prepare('SELECT * FROM facts ORDER BY timestamp DESC LIMIT ?').all(limit) as any[];\n\n return rows.map(row => ({\n id: row.id,\n fact: row.fact,\n source: row.source,\n when: row.timestamp || row.when,\n tags: JSON.parse(row.tags || '[]'),\n confidence: row.confidence ?? 0.8,\n }));\n }\n\n /**\n * Query blockers from warm storage with expanded tag matching\n */\n async queryBlockers(query: ContextQuery): Promise<Blocker[]> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n let sql = 'SELECT * FROM blockers WHERE resolvedAt IS NULL';\n const params: any[] = [];\n\n if (query.tags && query.tags.length > 0) {\n sql += ' AND (' + query.tags.map(() => '(tags LIKE ? OR expandedTags LIKE ?)').join(' OR ') + ')';\n for (const tag of query.tags) {\n params.push(`%\"${tag}\"%`, `%\"${tag}\"%`);\n }\n }\n\n sql += \" ORDER BY CASE impact WHEN 'critical' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 ELSE 4 END, timestamp DESC\";\n\n if (query.limit) {\n sql += ' LIMIT ?';\n params.push(query.limit);\n }\n\n const rows = this.warmDb.prepare(sql).all(...params) as any[];\n\n return rows.map(row => ({\n id: row.id,\n blocker: row.blocker,\n impact: row.impact,\n affectedAreas: JSON.parse(row.affectedAreas),\n when: row.when,\n resolvedAt: row.resolvedAt,\n resolution: row.resolution,\n tags: JSON.parse(row.tags)\n }));\n }\n\n /**\n * Get hot cache item\n */\n getHot<T>(key: string): T | undefined {\n return this.hotCache.get(key);\n }\n\n /**\n * Set hot cache item\n */\n setHot<T>(key: string, value: T): void {\n this.hotCache.set(key, value);\n }\n\n /**\n * Clear hot cache\n */\n clearHot(): void {\n this.hotCache.clear();\n }\n\n /**\n * Store a nudge in warm storage\n */\n async storeNudge(nudge: Nudge): Promise<void> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const stmt = this.warmDb.prepare(`\n INSERT OR REPLACE INTO nudges\n (id, message, severity, file, category, goalId, timestamp, resolved, resolvedAt, resolution, dismissed, priority, suggestedAction, relatedIssues, metadata)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n stmt.run(\n nudge.id,\n nudge.message,\n nudge.severity,\n nudge.file || null,\n nudge.category || null,\n nudge.goalId || null,\n nudge.timestamp,\n nudge.resolved ? 1 : 0,\n nudge.resolvedAt || null,\n nudge.resolution || null,\n nudge.dismissed ? 1 : 0,\n nudge.priority,\n nudge.suggestedAction || null,\n JSON.stringify(nudge.relatedIssues || []),\n JSON.stringify(nudge.metadata || {})\n );\n }\n\n /**\n * Query nudges from warm storage\n */\n async queryNudges(filters?: {\n resolved?: boolean;\n severity?: string;\n file?: string;\n category?: string;\n goalId?: string;\n limit?: number;\n }): Promise<Nudge[]> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n let sql = 'SELECT * FROM nudges WHERE 1=1';\n const params: any[] = [];\n\n if (filters?.resolved !== undefined) {\n sql += ' AND resolved = ?';\n params.push(filters.resolved ? 1 : 0);\n }\n\n if (filters?.severity) {\n sql += ' AND severity = ?';\n params.push(filters.severity);\n }\n\n if (filters?.file) {\n sql += ' AND file = ?';\n params.push(filters.file);\n }\n\n if (filters?.category) {\n sql += ' AND category = ?';\n params.push(filters.category);\n }\n\n if (filters?.goalId) {\n sql += ' AND goalId = ?';\n params.push(filters.goalId);\n }\n\n sql += ' ORDER BY timestamp DESC';\n\n if (filters?.limit) {\n sql += ' LIMIT ?';\n params.push(filters.limit);\n }\n\n const rows = this.warmDb.prepare(sql).all(...params) as any[];\n\n return rows.map(row => ({\n id: row.id,\n message: row.message,\n severity: row.severity,\n file: row.file || undefined,\n category: row.category || undefined,\n goalId: row.goalId || undefined,\n timestamp: row.timestamp,\n resolved: Boolean(row.resolved),\n resolvedAt: row.resolvedAt || undefined,\n resolution: row.resolution || undefined,\n dismissed: Boolean(row.dismissed),\n priority: row.priority,\n suggestedAction: row.suggestedAction || undefined,\n relatedIssues: JSON.parse(row.relatedIssues || '[]'),\n metadata: JSON.parse(row.metadata || '{}'),\n }));\n }\n\n /**\n * Mark a nudge as resolved\n */\n async resolveNudge(nudgeId: string, resolution: 'dismissed' | 'fixed' | 'auto-fixed'): Promise<void> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const now = new Date().toISOString();\n \n this.warmDb.prepare(`\n UPDATE nudges \n SET resolved = 1, resolvedAt = ?, resolution = ?, dismissed = ?\n WHERE id = ?\n `).run(now, resolution, resolution === 'dismissed' ? 1 : 0, nudgeId);\n }\n\n /**\n * Mark a nudge as dismissed\n */\n async dismissNudge(nudgeId: string): Promise<void> {\n await this.resolveNudge(nudgeId, 'dismissed');\n }\n\n /**\n * Mark a nudge as fixed (automatically called when issues are resolved)\n */\n async markNudgeFixed(nudgeId: string): Promise<void> {\n await this.resolveNudge(nudgeId, 'fixed');\n }\n\n /**\n * Clear all nudges (mark all as resolved)\n */\n async clearAllNudges(): Promise<void> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const now = new Date().toISOString();\n \n this.warmDb.prepare(`\n UPDATE nudges \n SET resolved = 1, resolvedAt = ?, resolution = 'dismissed'\n WHERE resolved = 0\n `).run(now);\n }\n\n /**\n * Resolve nudges for a goal violation that was fixed in a specific file.\n * Called when a file is rescanned and no longer has violations for that goal.\n */\n async resolveNudgesForGoalViolation(file: string, goalDescription: string, _workDir?: string): Promise<number> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const goalPattern = `%Goal \"${goalDescription.replace(/\"/g, '\"\"')}\"%`;\n const fileAlt = file.replace(/\\\\/g, '/');\n const rows = this.warmDb.prepare(`\n SELECT id FROM nudges \n WHERE resolved = 0 \n AND (file = ? OR file = ?)\n AND message LIKE ?\n `).all(file, fileAlt, goalPattern) as { id: string }[];\n\n const now = new Date().toISOString();\n let resolved = 0;\n for (const row of rows) {\n this.warmDb.prepare(`\n UPDATE nudges SET resolved = 1, resolvedAt = ?, resolution = 'auto-fixed'\n WHERE id = ?\n `).run(now, row.id);\n resolved++;\n }\n return resolved;\n }\n\n /**\n * Resolve all nudges for a specific goal (used when goal is achieved or deleted)\n */\n async resolveNudgesForGoal(goalDescription: string): Promise<number> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const goalPattern = `%Goal \"${goalDescription.replace(/\"/g, '\"\"')}\"%`;\n const now = new Date().toISOString();\n \n const result = this.warmDb.prepare(`\n UPDATE nudges \n SET resolved = 1, resolvedAt = ?, resolution = 'goal-achieved'\n WHERE resolved = 0 AND message LIKE ?\n `).run(now, goalPattern);\n\n return result.changes;\n }\n\n /**\n * Resolve nudges for files that no longer exist\n */\n async resolveNudgesForMissingFiles(): Promise<number> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const { existsSync } = await import('fs');\n const rows = this.warmDb.prepare(`\n SELECT id, file FROM nudges WHERE resolved = 0 AND file IS NOT NULL\n `).all() as { id: string; file: string }[];\n\n const now = new Date().toISOString();\n let resolved = 0;\n for (const row of rows) {\n if (row.file && !existsSync(row.file)) {\n this.warmDb.prepare(`\n UPDATE nudges SET resolved = 1, resolvedAt = ?, resolution = 'file-deleted'\n WHERE id = ?\n `).run(now, row.id);\n resolved++;\n }\n }\n return resolved;\n }\n\n /**\n * Resolve nudges matching a pattern in the message (for type error clearing, etc.)\n */\n async resolveNudgesByPattern(messagePattern: string, resolution: string = 'auto-fixed'): Promise<number> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const now = new Date().toISOString();\n const result = this.warmDb.prepare(`\n UPDATE nudges \n SET resolved = 1, resolvedAt = ?, resolution = ?\n WHERE resolved = 0 AND message LIKE ?\n `).run(now, resolution, `%${messagePattern}%`);\n\n return result.changes;\n }\n\n /**\n * Auto-resolve nudges that match fixed issues\n * Called after a scan to mark nudges as fixed if their related issues are resolved\n */\n async autoResolveFixedNudges(resolvedIssueIds: string[]): Promise<number> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n if (resolvedIssueIds.length === 0) return 0;\n\n const now = new Date().toISOString();\n let resolved = 0;\n\n // Mark nudges as fixed if their related issues are in the resolved list\n for (const issueId of resolvedIssueIds) {\n const result = this.warmDb.prepare(`\n UPDATE nudges \n SET resolved = 1, resolvedAt = ?, resolution = 'auto-fixed'\n WHERE resolved = 0 \n AND (\n relatedIssues LIKE ? \n OR id = ?\n )\n `).run(now, `%\"${issueId}\"%`, issueId);\n \n resolved += result.changes;\n }\n\n return resolved;\n }\n\n /**\n * Store a gotcha in warm storage\n */\n async storeGotcha(gotcha: Gotcha): Promise<void> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const stmt = this.warmDb.prepare(`\n INSERT OR REPLACE INTO gotchas\n (id, message, confidence, riskLevel, recommendation, file, timestamp, precedentId, tags, evidence, resolved, resolvedAt, resolution)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `);\n\n stmt.run(\n gotcha.id,\n gotcha.message,\n gotcha.confidence,\n gotcha.riskLevel,\n gotcha.recommendation,\n gotcha.file || null,\n gotcha.timestamp,\n gotcha.precedentId || null,\n JSON.stringify(gotcha.tags || []),\n JSON.stringify(gotcha.evidence || { pastIncidents: [], matchingPatterns: [], relatedTickets: [] }),\n gotcha.resolved ? 1 : 0,\n gotcha.resolvedAt || null,\n gotcha.resolution || null\n );\n }\n\n /**\n * Query gotchas from warm storage\n */\n async queryGotchas(filters?: {\n resolved?: boolean;\n riskLevel?: string;\n file?: string;\n limit?: number;\n }): Promise<Gotcha[]> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n let sql = 'SELECT * FROM gotchas WHERE 1=1';\n const params: any[] = [];\n\n if (filters?.resolved !== undefined) {\n sql += ' AND resolved = ?';\n params.push(filters.resolved ? 1 : 0);\n }\n\n if (filters?.riskLevel) {\n sql += ' AND riskLevel = ?';\n params.push(filters.riskLevel);\n }\n\n if (filters?.file) {\n sql += ' AND file = ?';\n params.push(filters.file);\n }\n\n sql += ' ORDER BY timestamp DESC';\n\n if (filters?.limit) {\n sql += ' LIMIT ?';\n params.push(filters.limit);\n }\n\n const rows = this.warmDb.prepare(sql).all(...params) as any[];\n\n return rows.map(row => ({\n id: row.id,\n message: row.message,\n confidence: row.confidence,\n riskLevel: row.riskLevel,\n recommendation: row.recommendation,\n file: row.file || undefined,\n timestamp: row.timestamp,\n precedentId: row.precedentId || undefined,\n tags: JSON.parse(row.tags || '[]'),\n evidence: JSON.parse(row.evidence || '{\"pastIncidents\":[],\"matchingPatterns\":[],\"relatedTickets\":[]}'),\n resolved: Boolean(row.resolved),\n resolvedAt: row.resolvedAt || undefined,\n resolution: row.resolution || undefined,\n }));\n }\n\n /**\n * Get unresolved nudges count\n */\n async getUnresolvedNudgesCount(): Promise<number> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const result = this.warmDb.prepare('SELECT COUNT(*) as count FROM nudges WHERE resolved = 0').get() as { count: number };\n return result.count;\n }\n\n /**\n * Archive old data to cold storage\n */\n async archiveToCold(olderThanDays: number = 90): Promise<void> {\n if (!this.warmDb) await this.initialize();\n if (!this.warmDb) throw new Error('Database not initialized');\n\n const cutoffDate = new Date();\n cutoffDate.setDate(cutoffDate.getDate() - olderThanDays);\n const cutoff = cutoffDate.toISOString();\n\n // Export to cold storage\n const coldDir = join(getTrieDirectory(this.workDir), 'cold');\n const archivePath = join(coldDir, `archive-${Date.now()}.json`);\n\n const governance = this.warmDb.prepare('SELECT * FROM governance WHERE timestamp < ? AND accessCount < 3').all(cutoff);\n const facts = this.warmDb.prepare('SELECT * FROM facts WHERE timestamp < ? AND accessCount < 3').all(cutoff);\n const blockers = this.warmDb.prepare('SELECT * FROM blockers WHERE timestamp < ? AND resolvedAt IS NOT NULL').all(cutoff);\n const questions = this.warmDb.prepare('SELECT * FROM questions WHERE timestamp < ? AND answeredAt IS NOT NULL').all(cutoff);\n const nudges = this.warmDb.prepare('SELECT * FROM nudges WHERE timestamp < ? AND resolved = 1').all(cutoff);\n const gotchas = this.warmDb.prepare('SELECT * FROM gotchas WHERE timestamp < ? AND resolved = 1').all(cutoff);\n\n await writeFile(archivePath, JSON.stringify({ governance, facts, blockers, questions, nudges, gotchas }, null, 2));\n\n // Delete from warm storage\n this.warmDb.prepare('DELETE FROM governance WHERE timestamp < ? AND accessCount < 3').run(cutoff);\n this.warmDb.prepare('DELETE FROM facts WHERE timestamp < ? AND accessCount < 3').run(cutoff);\n this.warmDb.prepare('DELETE FROM blockers WHERE timestamp < ? AND resolvedAt IS NOT NULL').run(cutoff);\n this.warmDb.prepare('DELETE FROM questions WHERE timestamp < ? AND answeredAt IS NOT NULL').run(cutoff);\n this.warmDb.prepare('DELETE FROM nudges WHERE timestamp < ? AND resolved = 1').run(cutoff);\n this.warmDb.prepare('DELETE FROM gotchas WHERE timestamp < ? AND resolved = 1').run(cutoff);\n }\n\n /**\n * Close database connection\n */\n close(): void {\n if (this.warmDb) {\n this.warmDb.close();\n this.warmDb = null;\n }\n }\n}\n\n/**\n * Get storage instance for working directory\n */\nconst storageInstances = new Map<string, TieredStorage>();\n\nexport function getStorage(workDir: string): TieredStorage {\n if (!storageInstances.has(workDir)) {\n storageInstances.set(workDir, new TieredStorage(workDir));\n }\n return storageInstances.get(workDir)!;\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/memory/ledger.ts","../src/utils/file-lock.ts","../src/agent/git.ts","../src/utils/command-runner.ts","../src/utils/audit-logger.ts","../src/memory/crypto-keys.ts","../src/memory/git-integration.ts"],"sourcesContent":["import { createHash } from 'crypto';\nimport { mkdir, readFile, writeFile, stat, unlink } 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 { withFileLock } from '../utils/file-lock.js';\nimport { getWorkingDirectory, getTrieDirectory } from '../utils/workspace.js';\nimport { getLastCommit, isGitRepo } from '../agent/git.js';\nimport type { StoredIssue } from './issue-store.js';\nimport { signHash, verifyHashSignature, hasSigningKey, type SignatureData } from './crypto-keys.js';\nimport { autoCommitLedger, ensureKeysIgnored } from './git-integration.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 status?: 'active' | 'corrected' | 'false-positive';\n correctedBy?: string; // Entry ID that corrects this\n correction?: string; // Reason for correction\n correctionTimestamp?: string; // When the correction was made\n // Semantic content for autonomous agent awareness\n issue?: string; // What was wrong (for ambient context)\n fix?: string; // How to fix it (for autonomous learning)\n // Digital signature fields\n signature?: string; // Ed25519 signature of entry hash\n publicKey?: string; // Public key that signed this\n signedAt?: string; // When the entry was signed\n signatureAlgorithm?: 'Ed25519';\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\n/**\n * Wrapper format for optimistic concurrency control\n * The contentHash allows detection of concurrent modifications\n */\nexport interface LedgerFile {\n _format: 'ledger-v2';\n _contentHash: string; // SHA-256 of JSON.stringify(blocks)\n _lastModified: string;\n blocks: LedgerBlock[];\n}\n\n/**\n * Error thrown when optimistic concurrency check fails\n */\nexport class ConcurrentModificationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConcurrentModificationError';\n }\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\n/**\n * Sign a ledger entry with Ed25519\n * \n * Signs the entry hash to prove authenticity and detect tampering.\n * Creates or uses existing signing key from .trie/keys/\n */\nexport async function signLedgerEntry(entry: LedgerEntry, workDir?: string): Promise<LedgerEntry> {\n try {\n const signatureData = await signHash(entry.hash, workDir);\n \n return {\n ...entry,\n signature: signatureData.signature,\n publicKey: signatureData.publicKey,\n signedAt: signatureData.signedAt,\n signatureAlgorithm: 'Ed25519'\n };\n } catch (error) {\n console.error('Failed to sign ledger entry:', error);\n // Return unsigned entry if signing fails\n return entry;\n }\n}\n\n/**\n * Verify a ledger entry signature\n * \n * Returns true if signature is valid, false otherwise.\n * Unsigned entries return true (for backward compatibility).\n */\nexport async function verifyLedgerEntry(entry: LedgerEntry): Promise<boolean> {\n // Unsigned entries are considered valid (backward compatibility)\n if (!entry.signature || !entry.publicKey) {\n return true;\n }\n \n // Check algorithm\n if (entry.signatureAlgorithm !== 'Ed25519') {\n console.error('Unsupported signature algorithm:', entry.signatureAlgorithm);\n return false;\n }\n \n const signatureData: SignatureData = {\n signature: entry.signature,\n publicKey: entry.publicKey,\n algorithm: 'Ed25519',\n signedAt: entry.signedAt || ''\n };\n \n return await verifyHashSignature(entry.hash, signatureData);\n}\n\n/**\n * Verify all entries in a block\n */\nexport async function verifyBlockSignatures(block: LedgerBlock): Promise<{ valid: boolean; invalidEntries: string[] }> {\n const invalidEntries: string[] = [];\n \n for (const entry of block.entries) {\n const isValid = await verifyLedgerEntry(entry);\n if (!isValid) {\n invalidEntries.push(entry.id);\n }\n }\n \n return {\n valid: invalidEntries.length === 0,\n invalidEntries\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 const ledgerPath = join(memoryDir, LEDGER_FILENAME);\n\n // Use file locking to prevent concurrent write conflicts\n return withFileLock(ledgerPath, async () => {\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 // Create entries with semantic content for autonomous agent awareness\n const shouldSign = hasSigningKey(projectDir);\n let 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 status: 'active' as const,\n // Include semantic content for ambient awareness\n issue: issue.issue,\n fix: issue.fix,\n }));\n \n // Sign all entries if key exists\n if (shouldSign) {\n entries = await Promise.all(entries.map(entry => signLedgerEntry(entry, projectDir)));\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 // Use internal save since lock is already held\n await saveLedgerInternal(blocks, projectDir);\n \n // Level 2: Auto-commit to git (if enabled)\n if (await isGitRepo(projectDir)) {\n // Ensure signing keys are in .gitignore\n await ensureKeysIgnored(projectDir);\n \n // Auto-commit ledger changes\n const commitMessage = `ledger: append ${entries.length} ${entries.length === 1 ? 'entry' : 'entries'}`;\n await autoCommitLedger(projectDir, commitMessage);\n }\n \n return block;\n }, { timeout: 15000 }); // 15s timeout for ledger operations\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} block hash mismatch` };\n }\n \n // Verify signatures for signed entries\n const signatureVerification = await verifyBlockSignatures(block);\n if (!signatureVerification.valid) {\n return { \n valid: false, \n error: `Block ${i} has invalid signatures: ${signatureVerification.invalidEntries.join(', ')}` \n };\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 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 chainHeight,\n ...(gitCommit && { gitCommit }),\n };\n}\n\n/**\n * Load ledger blocks from file\n * Supports both legacy array format and new wrapper format with content hash\n */\nasync function loadLedger(projectDir: string): Promise<LedgerBlock[]> {\n const result = await loadLedgerWithHash(projectDir);\n return result.blocks;\n}\n\n/**\n * Load ledger blocks along with content hash for optimistic concurrency\n * Returns both the blocks and the hash that can be used to verify no concurrent modifications\n */\nasync function loadLedgerWithHash(projectDir: string): Promise<{ blocks: LedgerBlock[]; contentHash: string }> {\n const ledgerPath = join(getTrieDirectory(projectDir), 'memory', LEDGER_FILENAME);\n try {\n if (!existsSync(ledgerPath)) {\n return { blocks: [], contentHash: sha256('[]') };\n }\n const content = await readFile(ledgerPath, 'utf-8');\n const parsed = JSON.parse(content);\n \n // Check if it's the new wrapper format\n if (parsed && parsed._format === 'ledger-v2') {\n const file = parsed as LedgerFile;\n return { \n blocks: file.blocks || [],\n contentHash: file._contentHash\n };\n }\n \n // Legacy format: plain array of blocks\n if (!Array.isArray(parsed)) {\n return { blocks: [], contentHash: sha256('[]') };\n }\n \n // Calculate hash for legacy format\n const blocks = parsed as LedgerBlock[];\n const contentHash = sha256(JSON.stringify(blocks));\n return { blocks, contentHash };\n } catch {\n return { blocks: [], contentHash: sha256('[]') };\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\n/**\n * Load ledger with content hash for optimistic concurrency control\n * \n * Use this when you need to detect concurrent modifications:\n * 1. Load with getLedgerBlocksWithHash()\n * 2. Modify blocks\n * 3. Save with saveLedgerOptimistic() passing the original hash\n * \n * @returns blocks and contentHash that can be used to verify no concurrent modifications\n */\nexport async function getLedgerBlocksWithHash(workDir?: string): Promise<{ blocks: LedgerBlock[]; contentHash: string }> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n return loadLedgerWithHash(projectDir);\n}\n\n/**\n * Save ledger with optimistic concurrency control\n * \n * Verifies the ledger hasn't been modified since it was loaded before saving.\n * Use with getLedgerBlocksWithHash() to implement optimistic locking.\n * \n * @param blocks - The modified blocks to save\n * @param expectedHash - The content hash from when the ledger was loaded\n * @param workDir - Working directory\n * @throws ConcurrentModificationError if the ledger was modified by another process\n */\nexport async function saveLedgerOptimistic(\n blocks: LedgerBlock[],\n expectedHash: string,\n workDir?: string\n): Promise<void> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const ledgerPath = join(memoryDir, LEDGER_FILENAME);\n \n // Use file locking AND optimistic concurrency for maximum safety\n await withFileLock(ledgerPath, async () => {\n await saveLedgerWithConcurrencyCheck(blocks, projectDir, expectedHash);\n }, { timeout: 10000 });\n}\n\n/**\n * Save ledger with file locking (use for standalone saves)\n */\nasync function saveLedger(blocks: LedgerBlock[], projectDir: string): Promise<void> {\n const ledgerPath = join(getTrieDirectory(projectDir), 'memory', LEDGER_FILENAME);\n await withFileLock(ledgerPath, async () => {\n await saveLedgerWithFormat(ledgerPath, blocks);\n }, { timeout: 10000 });\n}\n\n/**\n * Save ledger without acquiring lock (use when lock is already held)\n */\nasync function saveLedgerInternal(blocks: LedgerBlock[], projectDir: string): Promise<void> {\n const ledgerPath = join(getTrieDirectory(projectDir), 'memory', LEDGER_FILENAME);\n await saveLedgerWithFormat(ledgerPath, blocks);\n}\n\n/**\n * Save ledger with optimistic concurrency check\n * \n * @param expectedHash - If provided, verifies the file hasn't changed since it was loaded\n * @throws ConcurrentModificationError if expectedHash doesn't match current file\n */\nasync function saveLedgerWithConcurrencyCheck(\n blocks: LedgerBlock[],\n projectDir: string,\n expectedHash: string\n): Promise<void> {\n const ledgerPath = join(getTrieDirectory(projectDir), 'memory', LEDGER_FILENAME);\n \n // Read current hash\n const { contentHash: currentHash } = await loadLedgerWithHash(projectDir);\n \n if (currentHash !== expectedHash) {\n throw new ConcurrentModificationError(\n `Ledger was modified by another process. ` +\n `Expected hash: ${expectedHash.slice(0, 16)}..., ` +\n `Current hash: ${currentHash.slice(0, 16)}...`\n );\n }\n \n await saveLedgerWithFormat(ledgerPath, blocks);\n}\n\n/**\n * Internal helper to save ledger in the wrapper format\n */\nasync function saveLedgerWithFormat(ledgerPath: string, blocks: LedgerBlock[]): Promise<void> {\n const blocksJson = JSON.stringify(blocks);\n const contentHash = sha256(blocksJson);\n \n const ledgerFile: LedgerFile = {\n _format: 'ledger-v2',\n _contentHash: contentHash,\n _lastModified: new Date().toISOString(),\n blocks\n };\n \n await atomicWriteJSON(ledgerPath, ledgerFile);\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 const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const ledgerPath = join(memoryDir, LEDGER_FILENAME);\n\n // Ensure shared storage exists\n await initializeSharedLedger(projectDir);\n\n // Use file locking for the entire sync operation\n return withFileLock(ledgerPath, async () => {\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 (always merge entries, never discard)\n const mergeResult = await mergeChains(localBlocks, sharedBlocks, 'timestamp');\n\n // Save merged chain locally (lock already held)\n await saveLedgerInternal(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 }, { timeout: 30000 }); // 30s timeout for sync operations\n}\n\nexport async function pushLedgerToShared(workDir?: string): Promise<void> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const ledgerPath = join(memoryDir, LEDGER_FILENAME);\n\n // Ensure shared storage exists\n await initializeSharedLedger(projectDir);\n\n // Use file locking for the entire push operation\n await withFileLock(ledgerPath, async () => {\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 const blockAuthor = block.author;\n if (blockAuthor) {\n if (!manifest.index.byAuthor[blockAuthor]) {\n manifest.index.byAuthor[blockAuthor] = [];\n }\n if (!manifest.index.byAuthor[blockAuthor].includes(`active/${blockFilename}`)) {\n manifest.index.byAuthor[blockAuthor].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 }, { timeout: 30000 }); // 30s timeout for push operations\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 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\n/**\n * Resolve conflicts by ALWAYS merging entries from both blocks.\n * This prevents data loss - no entries are ever discarded.\n * \n * The strategy parameter now only affects metadata (author, timestamps),\n * not the actual entry merging which always includes all entries.\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 // ALWAYS merge entries from both blocks to prevent data loss\n const mergedBlock = mergeBlockEntries(conflict.localBlock, conflict.remoteBlock);\n \n // Mark that this block resolved a conflict\n mergedBlock.conflictResolved = true;\n \n // Use strategy only for determining author attribution when merged\n switch (strategy) {\n case 'timestamp':\n // Prefer author from the more recently updated block\n if (conflict.remoteBlock.updatedAt > conflict.localBlock.updatedAt) {\n mergedBlock.author = `${conflict.remoteBlock.author}+${conflict.localBlock.author}`;\n } else {\n mergedBlock.author = `${conflict.localBlock.author}+${conflict.remoteBlock.author}`;\n }\n break;\n \n case 'longest':\n // Prefer author from block with more entries\n if (conflict.remoteBlock.entries.length > conflict.localBlock.entries.length) {\n mergedBlock.author = `${conflict.remoteBlock.author}+${conflict.localBlock.author}`;\n } else {\n mergedBlock.author = `${conflict.localBlock.author}+${conflict.remoteBlock.author}`;\n }\n break;\n \n case 'manual':\n default:\n mergedBlock.author = `${conflict.localBlock.author}+${conflict.remoteBlock.author}`;\n break;\n }\n \n return mergedBlock;\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 chainHeight: index,\n syncedAt: new Date().toISOString(),\n ...(lastCommit?.hash && { gitCommit: lastCommit.hash }),\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 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\n/** Load blocks from archived tar.gz - for read-back from archives */\nexport async 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 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// ==================== Entry Correction Functions (Immutable Ledger) ====================\n\nexport interface CorrectionResult {\n success: boolean;\n correctedEntries: number;\n correctionBlock?: SyncableLedgerBlock;\n error?: string;\n}\n\n/**\n * Mark ledger entries as corrected by adding a correction entry to the ledger.\n * This maintains immutability - original entries remain in the chain for audit trail.\n * \n * @param entryIds - IDs of entries to mark as corrected\n * @param reason - Reason for the correction (e.g., \"false positive\", \"duplicate\", \"incorrect detection\")\n * @param correctionType - Type of correction: 'corrected' or 'false-positive'\n * @param workDir - Working directory\n * @param author - Author of the correction\n */\nexport async function correctLedgerEntries(\n entryIds: string[],\n reason: string,\n correctionType: 'corrected' | 'false-positive' = 'corrected',\n workDir?: string,\n author?: string\n): Promise<CorrectionResult> {\n if (entryIds.length === 0) {\n return {\n success: false,\n correctedEntries: 0,\n error: 'No entry IDs provided'\n };\n }\n\n if (!reason || reason.trim().length === 0) {\n return {\n success: false,\n correctedEntries: 0,\n error: 'Correction reason is required'\n };\n }\n\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const ledgerPath = join(memoryDir, LEDGER_FILENAME);\n\n // Use file locking to prevent concurrent write conflicts\n return withFileLock(ledgerPath, async () => {\n const blocks = await loadLedger(projectDir) as SyncableLedgerBlock[];\n\n // Find entries to correct\n const entriesToCorrect: LedgerEntry[] = [];\n for (const block of blocks) {\n for (const entry of block.entries) {\n if (entryIds.includes(entry.id) && entry.status === 'active') {\n entriesToCorrect.push(entry);\n }\n }\n }\n\n if (entriesToCorrect.length === 0) {\n return {\n success: false,\n correctedEntries: 0,\n error: 'No active entries found with the provided IDs'\n };\n }\n\n try {\n const now = new Date().toISOString();\n const isRepo = await isGitRepo(projectDir);\n const lastCommit = isRepo ? await getLastCommit(projectDir) : null;\n const correctionAuthor = author || lastCommit?.author || 'unknown';\n\n // Create correction entries (append-only: we add new entries that mark the old ones as corrected)\n const correctionEntries: LedgerEntry[] = entriesToCorrect.map(entry => {\n const correctionId = `correction-${entry.id}-${Date.now()}`;\n return {\n id: correctionId,\n hash: sha256(`${correctionId}:${entry.hash}:${reason}:${now}`),\n severity: 'info',\n file: entry.file,\n agent: 'ledger-correction',\n timestamp: now,\n status: 'active',\n correction: `Correcting entry ${entry.id}: ${reason}`,\n correctedBy: entry.id,\n };\n });\n\n // Update original entries in their blocks to mark them as corrected\n for (const block of blocks) {\n let blockModified = false;\n for (const entry of block.entries) {\n if (entryIds.includes(entry.id) && entry.status === 'active') {\n entry.status = correctionType;\n entry.correctionTimestamp = now;\n entry.correction = reason;\n blockModified = true;\n }\n }\n \n if (blockModified) {\n // Recalculate merkle root and block hash\n block.merkleRoot = computeMerkleRoot(block.entries.map(e => e.hash));\n block.blockHash = computeBlockHash(\n block.previousHash,\n block.merkleRoot,\n block.date,\n block.version\n );\n block.updatedAt = now;\n }\n }\n\n // Save updated blocks (lock already held)\n await saveLedgerInternal(blocks, projectDir);\n\n // Note: appendIssuesToLedger will acquire its own lock, which is fine\n // since we've released ours by returning from this callback\n // We need to save correction entries without the recursive lock\n const correctionBlock = await appendCorrectionEntries(\n correctionEntries,\n projectDir,\n correctionAuthor\n );\n\n return {\n success: true,\n correctedEntries: entriesToCorrect.length,\n ...(correctionBlock && { correctionBlock }),\n };\n } catch (error) {\n return {\n success: false,\n correctedEntries: 0,\n error: `Failed to correct entries: ${error instanceof Error ? error.message : 'Unknown error'}`\n };\n }\n }, { timeout: 15000 });\n}\n\n/**\n * Internal helper to append correction entries without re-acquiring lock\n * Called from within correctLedgerEntries which already holds the lock\n */\nasync function appendCorrectionEntries(\n correctionEntries: LedgerEntry[],\n projectDir: string,\n author: string\n): Promise<SyncableLedgerBlock | null> {\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 previousBlock = blocks[blocks.length - 1];\n const block = previousBlock && previousBlock.date === today\n ? previousBlock\n : createSyncableBlock(today, now, previousBlock?.blockHash ?? GENESIS_HASH, author, undefined, blocks.length);\n\n if (block !== previousBlock) {\n blocks.push(block);\n }\n\n block.entries = [...block.entries, ...correctionEntries];\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 saveLedgerInternal(blocks, projectDir);\n return block;\n}\n\n/**\n * Get all entries from the ledger, optionally filtering by status.\n * By default, only returns active entries (excludes corrected/false-positives).\n */\nexport async function getLedgerEntries(\n workDir?: string,\n includeStatus?: Array<'active' | 'corrected' | 'false-positive'>\n): Promise<LedgerEntry[]> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const blocks = await loadLedger(projectDir);\n \n const statusFilter = includeStatus || ['active'];\n const entries: LedgerEntry[] = [];\n \n for (const block of blocks) {\n for (const entry of block.entries) {\n const entryStatus = entry.status || 'active';\n if (statusFilter.includes(entryStatus as any)) {\n entries.push(entry);\n }\n }\n }\n \n return entries;\n}\n\n/**\n * Get correction history for specific entry IDs.\n * Returns the original entry and any correction entries.\n */\nexport async function getEntryCorrectionHistory(\n entryIds: string[],\n workDir?: string\n): Promise<Map<string, { original: LedgerEntry; corrections: LedgerEntry[] }>> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const blocks = await loadLedger(projectDir);\n \n const history = new Map<string, { original: LedgerEntry; corrections: LedgerEntry[] }>();\n \n for (const entryId of entryIds) {\n const corrections: LedgerEntry[] = [];\n let original: LedgerEntry | null = null;\n \n for (const block of blocks) {\n for (const entry of block.entries) {\n if (entry.id === entryId) {\n original = entry;\n }\n if (entry.correctedBy === entryId) {\n corrections.push(entry);\n }\n }\n }\n \n if (original) {\n history.set(entryId, { original, corrections });\n }\n }\n \n return history;\n}\n\n/**\n * Get statistics about ledger corrections\n */\nexport async function getCorrectionStats(workDir?: string): Promise<{\n totalEntries: number;\n activeEntries: number;\n correctedEntries: number;\n falsePositives: number;\n correctionRate: number;\n}> {\n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const blocks = await loadLedger(projectDir);\n \n let totalEntries = 0;\n let activeEntries = 0;\n let correctedEntries = 0;\n let falsePositives = 0;\n \n for (const block of blocks) {\n for (const entry of block.entries) {\n totalEntries++;\n const status = entry.status || 'active';\n \n if (status === 'active') activeEntries++;\n else if (status === 'corrected') correctedEntries++;\n else if (status === 'false-positive') falsePositives++;\n }\n }\n \n const correctionRate = totalEntries > 0 \n ? ((correctedEntries + falsePositives) / totalEntries) * 100 \n : 0;\n \n return {\n totalEntries,\n activeEntries,\n correctedEntries,\n falsePositives,\n correctionRate: Math.round(correctionRate * 100) / 100\n };\n}\n","/**\n * File Locking Utility\n * \n * Provides advisory file locking for coordinating concurrent access\n * to shared files like the ledger and issue store.\n * \n * Uses the atomic create-if-not-exists pattern (O_CREAT | O_EXCL)\n * for cross-platform lock acquisition.\n * \n * Features:\n * - Stale lock detection and cleanup\n * - Configurable timeout with exponential backoff\n * - Process ID tracking for debugging\n * - Automatic cleanup on process exit\n */\n\nimport { open, unlink, readFile, stat, mkdir } from 'fs/promises';\nimport { existsSync } from 'fs';\nimport { dirname } from 'path';\n\nexport interface FileLockOptions {\n /**\n * Maximum time to wait for lock acquisition (ms)\n * @default 10000\n */\n timeout?: number;\n \n /**\n * Initial retry delay (ms), doubles on each retry\n * @default 50\n */\n retryDelay?: number;\n \n /**\n * Maximum retry delay (ms)\n * @default 500\n */\n maxRetryDelay?: number;\n \n /**\n * Time after which a lock is considered stale and can be forcibly acquired (ms)\n * This handles crashed processes that didn't clean up their locks\n * @default 30000\n */\n staleTimeout?: number;\n}\n\nexport interface LockInfo {\n pid: number;\n timestamp: number;\n hostname: string;\n}\n\nconst activeLocks = new Set<string>();\n\n// Cleanup locks on process exit\nfunction setupCleanupHandler() {\n const cleanup = () => {\n for (const lockPath of activeLocks) {\n try {\n // Synchronous unlink for exit handler\n const fs = require('fs');\n if (fs.existsSync(lockPath)) {\n fs.unlinkSync(lockPath);\n }\n } catch {\n // Best effort cleanup\n }\n }\n };\n \n process.on('exit', cleanup);\n process.on('SIGINT', () => { cleanup(); process.exit(130); });\n process.on('SIGTERM', () => { cleanup(); process.exit(143); });\n}\n\nlet cleanupHandlerInstalled = false;\n\n/**\n * Execute a function with an exclusive file lock\n * \n * @param filePath - The file to lock (lock file will be `${filePath}.lock`)\n * @param fn - The async function to execute while holding the lock\n * @param options - Lock options\n * @returns The result of the function\n * @throws Error if lock cannot be acquired within timeout\n * \n * @example\n * ```typescript\n * await withFileLock('/path/to/data.json', async () => {\n * const data = await readFile('/path/to/data.json', 'utf-8');\n * const modified = JSON.parse(data);\n * modified.count++;\n * await writeFile('/path/to/data.json', JSON.stringify(modified));\n * });\n * ```\n */\nexport async function withFileLock<T>(\n filePath: string,\n fn: () => Promise<T>,\n options: FileLockOptions = {}\n): Promise<T> {\n const {\n timeout = 10000,\n retryDelay = 50,\n maxRetryDelay = 500,\n staleTimeout = 30000,\n } = options;\n \n const lockPath = `${filePath}.lock`;\n const start = Date.now();\n let currentDelay = retryDelay;\n \n // Install cleanup handler on first use\n if (!cleanupHandlerInstalled) {\n setupCleanupHandler();\n cleanupHandlerInstalled = true;\n }\n \n // Ensure parent directory exists before any lock operations\n await mkdir(dirname(lockPath), { recursive: true });\n \n // Try to acquire the lock\n while (true) {\n try {\n // Check for stale lock first\n await cleanupStaleLock(lockPath, staleTimeout);\n \n // Try atomic create (O_CREAT | O_EXCL equivalent)\n const lockInfo: LockInfo = {\n pid: process.pid,\n timestamp: Date.now(),\n hostname: require('os').hostname(),\n };\n \n const handle = await open(lockPath, 'wx');\n await handle.writeFile(JSON.stringify(lockInfo));\n await handle.close();\n \n // Track active lock for cleanup\n activeLocks.add(lockPath);\n \n try {\n return await fn();\n } finally {\n // Release lock\n activeLocks.delete(lockPath);\n await unlink(lockPath).catch(() => {\n // Lock file may have been removed by stale cleanup\n });\n }\n } catch (err: any) {\n if (err.code !== 'EEXIST') {\n // Unexpected error (e.g., permission denied)\n throw err;\n }\n \n // Lock exists, check timeout\n if (Date.now() - start > timeout) {\n // Try to get info about who holds the lock\n let lockHolder = 'unknown';\n try {\n const content = await readFile(lockPath, 'utf-8');\n const info = JSON.parse(content) as LockInfo;\n lockHolder = `PID ${info.pid} on ${info.hostname}`;\n } catch {\n // Can't read lock info\n }\n \n throw new Error(\n `Timeout acquiring lock for ${filePath} after ${timeout}ms. ` +\n `Lock held by: ${lockHolder}`\n );\n }\n \n // Wait with exponential backoff before retry\n await new Promise(resolve => setTimeout(resolve, currentDelay));\n currentDelay = Math.min(currentDelay * 2, maxRetryDelay);\n }\n }\n}\n\n/**\n * Clean up a stale lock file\n * \n * A lock is considered stale if:\n * 1. It's older than staleTimeout\n * 2. The process that created it is no longer running (on same machine)\n */\nasync function cleanupStaleLock(lockPath: string, staleTimeout: number): Promise<void> {\n if (!existsSync(lockPath)) {\n return;\n }\n \n try {\n const content = await readFile(lockPath, 'utf-8');\n const info = JSON.parse(content) as LockInfo;\n const lockAge = Date.now() - info.timestamp;\n \n // Check if lock is stale by age\n if (lockAge > staleTimeout) {\n console.warn(`[FileLock] Removing stale lock (age: ${Math.round(lockAge / 1000)}s): ${lockPath}`);\n await unlink(lockPath);\n return;\n }\n \n // Check if the process is still running (only works on same machine)\n const currentHostname = require('os').hostname();\n if (info.hostname === currentHostname) {\n if (!isProcessRunning(info.pid)) {\n console.warn(`[FileLock] Removing orphaned lock (PID ${info.pid} not running): ${lockPath}`);\n await unlink(lockPath);\n return;\n }\n }\n } catch {\n // If we can't read the lock file, it might be corrupted\n // Check by file age instead\n try {\n const stats = await stat(lockPath);\n const fileAge = Date.now() - stats.mtimeMs;\n if (fileAge > staleTimeout) {\n console.warn(`[FileLock] Removing stale/corrupted lock: ${lockPath}`);\n await unlink(lockPath);\n }\n } catch {\n // File doesn't exist or can't be accessed\n }\n }\n}\n\n/**\n * Check if a process is still running\n */\nfunction isProcessRunning(pid: number): boolean {\n try {\n // Sending signal 0 checks if process exists without affecting it\n process.kill(pid, 0);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Try to acquire a lock without blocking\n * \n * @returns true if lock was acquired, false if already locked\n */\nexport async function tryAcquireLock(\n filePath: string,\n options: { staleTimeout?: number } = {}\n): Promise<boolean> {\n const lockPath = `${filePath}.lock`;\n const { staleTimeout = 30000 } = options;\n \n await mkdir(dirname(lockPath), { recursive: true });\n \n try {\n await cleanupStaleLock(lockPath, staleTimeout);\n \n const lockInfo: LockInfo = {\n pid: process.pid,\n timestamp: Date.now(),\n hostname: require('os').hostname(),\n };\n \n const handle = await open(lockPath, 'wx');\n await handle.writeFile(JSON.stringify(lockInfo));\n await handle.close();\n \n activeLocks.add(lockPath);\n return true;\n } catch (err: any) {\n if (err.code === 'EEXIST') {\n return false;\n }\n throw err;\n }\n}\n\n/**\n * Release a previously acquired lock\n */\nexport async function releaseLock(filePath: string): Promise<void> {\n const lockPath = `${filePath}.lock`;\n activeLocks.delete(lockPath);\n await unlink(lockPath).catch(() => {});\n}\n\n/**\n * Check if a file is currently locked\n */\nexport async function isLocked(\n filePath: string,\n options: { staleTimeout?: number } = {}\n): Promise<boolean> {\n const lockPath = `${filePath}.lock`;\n const { staleTimeout = 30000 } = options;\n \n if (!existsSync(lockPath)) {\n return false;\n }\n \n // Check if lock is stale\n try {\n const content = await readFile(lockPath, 'utf-8');\n const info = JSON.parse(content) as LockInfo;\n const lockAge = Date.now() - info.timestamp;\n \n if (lockAge > staleTimeout) {\n return false; // Stale lock\n }\n \n // Check if process is still running\n const currentHostname = require('os').hostname();\n if (info.hostname === currentHostname && !isProcessRunning(info.pid)) {\n return false; // Orphaned lock\n }\n \n return true;\n } catch {\n return false;\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 './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 *\n * Audit functionality has been integrated into the decision ledger.\n * This module exists to keep legacy CLI/tooling paths working without the old skills system.\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\n","/**\n * Cryptographic Key Management\n * \n * Ed25519 signature support for ledger entries.\n * Keys are stored in .trie/keys/ directory.\n * \n * Usage:\n * - generateKeyPair() - Create new signing key\n * - getOrCreateKeyPair() - Get existing or create new\n * - signData() - Sign arbitrary data\n * - verifySignature() - Verify a signature\n */\n\nimport * as ed25519 from '@noble/ed25519';\nimport { randomBytes } from 'crypto';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport { getTrieDirectory } from '../utils/workspace.js';\n\nexport interface KeyPair {\n publicKey: string; // Hex-encoded public key\n privateKey: string; // Hex-encoded private key\n}\n\nexport interface SignatureData {\n signature: string;\n publicKey: string;\n algorithm: 'Ed25519';\n signedAt: string;\n}\n\n/**\n * Get keys directory path\n */\nfunction getKeysDirectory(workDir?: string): string {\n const trieDir = getTrieDirectory(workDir || process.cwd());\n return join(trieDir, 'keys');\n}\n\n/**\n * Get the default key file path\n */\nfunction getDefaultKeyPath(workDir?: string): string {\n return join(getKeysDirectory(workDir), 'signing-key.json');\n}\n\n/**\n * Generate a new Ed25519 key pair\n */\nexport async function generateKeyPair(): Promise<KeyPair> {\n // Generate 32 random bytes for private key\n const privateKeyBytes = randomBytes(32);\n const publicKeyBytes = await ed25519.getPublicKeyAsync(privateKeyBytes);\n \n return {\n publicKey: Buffer.from(publicKeyBytes).toString('hex'),\n privateKey: Buffer.from(privateKeyBytes).toString('hex')\n };\n}\n\n/**\n * Save key pair to disk (encrypted would be better, but starting simple)\n */\nexport function saveKeyPair(keyPair: KeyPair, workDir?: string): void {\n const keysDir = getKeysDirectory(workDir);\n \n // Create keys directory if it doesn't exist\n if (!existsSync(keysDir)) {\n mkdirSync(keysDir, { recursive: true });\n }\n \n const keyPath = getDefaultKeyPath(workDir);\n const keyData = {\n ...keyPair,\n createdAt: new Date().toISOString(),\n version: 1\n };\n \n writeFileSync(keyPath, JSON.stringify(keyData, null, 2), 'utf-8');\n \n // Warn about security\n console.error('⚠️ Signing key created at:', keyPath);\n console.error(' Keep this file secure and add to .gitignore');\n}\n\n/**\n * Load key pair from disk\n */\nexport function loadKeyPair(workDir?: string): KeyPair | null {\n const keyPath = getDefaultKeyPath(workDir);\n \n if (!existsSync(keyPath)) {\n return null;\n }\n \n try {\n const keyData = JSON.parse(readFileSync(keyPath, 'utf-8'));\n return {\n publicKey: keyData.publicKey,\n privateKey: keyData.privateKey\n };\n } catch (error) {\n console.error('Failed to load signing key:', error);\n return null;\n }\n}\n\n/**\n * Get existing key pair or create a new one\n */\nexport async function getOrCreateKeyPair(workDir?: string): Promise<KeyPair> {\n const existing = loadKeyPair(workDir);\n if (existing) {\n return existing;\n }\n \n const newKeyPair = await generateKeyPair();\n saveKeyPair(newKeyPair, workDir);\n return newKeyPair;\n}\n\n/**\n * Sign arbitrary data with private key\n */\nexport async function signData(data: string, privateKey: string): Promise<string> {\n const dataBytes = Buffer.from(data, 'utf-8');\n const privateKeyBytes = Buffer.from(privateKey, 'hex');\n const signatureBytes = await ed25519.signAsync(dataBytes, privateKeyBytes);\n \n return Buffer.from(signatureBytes).toString('hex');\n}\n\n/**\n * Verify a signature\n */\nexport async function verifySignature(\n data: string,\n signature: string,\n publicKey: string\n): Promise<boolean> {\n try {\n const dataBytes = Buffer.from(data, 'utf-8');\n const signatureBytes = Buffer.from(signature, 'hex');\n const publicKeyBytes = Buffer.from(publicKey, 'hex');\n \n return await ed25519.verifyAsync(signatureBytes, dataBytes, publicKeyBytes);\n } catch (error) {\n console.error('Signature verification failed:', error);\n return false;\n }\n}\n\n/**\n * Sign a data hash and return signature metadata\n */\nexport async function signHash(hash: string, workDir?: string): Promise<SignatureData> {\n const keyPair = await getOrCreateKeyPair(workDir);\n const signature = await signData(hash, keyPair.privateKey);\n \n return {\n signature,\n publicKey: keyPair.publicKey,\n algorithm: 'Ed25519',\n signedAt: new Date().toISOString()\n };\n}\n\n/**\n * Verify a hash signature\n */\nexport async function verifyHashSignature(\n hash: string,\n signatureData: SignatureData\n): Promise<boolean> {\n if (signatureData.algorithm !== 'Ed25519') {\n console.error('Unsupported signature algorithm:', signatureData.algorithm);\n return false;\n }\n \n return await verifySignature(hash, signatureData.signature, signatureData.publicKey);\n}\n\n/**\n * Get the public key for the current workspace\n */\nexport function getPublicKey(workDir?: string): string | null {\n const keyPair = loadKeyPair(workDir);\n return keyPair?.publicKey || null;\n}\n\n/**\n * Check if signing keys exist\n */\nexport function hasSigningKey(workDir?: string): boolean {\n const keyPath = getDefaultKeyPath(workDir);\n return existsSync(keyPath);\n}\n","/**\n * Git Integration for Ledger\n * \n * Auto-commit ledger changes to provide:\n * - Distributed backup (every clone has a copy)\n * - Git's content-addressable storage (tamper-evident)\n * - History tracking via commit graph\n * - Remote backup via push\n * \n * Usage:\n * - autoCommitLedger() - Commit ledger changes after append\n * - isGitIntegrationEnabled() - Check if Git integration is on\n */\n\nimport { exec } from 'child_process';\nimport { promisify } from 'util';\nimport { existsSync } from 'fs';\nimport { join } from 'path';\nimport { getTrieDirectory } from '../utils/workspace.js';\n\nconst execAsync = promisify(exec);\n\nexport interface GitCommitResult {\n committed: boolean;\n commitHash?: string;\n error?: string;\n}\n\n/**\n * Check if Git integration is enabled for this project\n * \n * Git integration is enabled if:\n * 1. Project is a git repo\n * 2. .trie/config.json has gitIntegration: true (or doesn't exist, defaults to true)\n */\nexport async function isGitIntegrationEnabled(workDir: string): Promise<boolean> {\n try {\n // Check if git repo\n const gitDir = join(workDir, '.git');\n if (!existsSync(gitDir)) {\n return false;\n }\n \n // Check config (default to true if config doesn't exist)\n const configPath = join(getTrieDirectory(workDir), 'config.json');\n if (!existsSync(configPath)) {\n return true; // Default: enabled\n }\n \n const config = JSON.parse(await import('fs/promises').then(fs => fs.readFile(configPath, 'utf-8')));\n return config.gitIntegration !== false;\n } catch {\n return false;\n }\n}\n\n/**\n * Auto-commit ledger changes\n * \n * Commits ledger.json to git with a structured commit message.\n * This provides distributed backup and tamper-evident history.\n */\nexport async function autoCommitLedger(workDir: string, message?: string): Promise<GitCommitResult> {\n try {\n const enabled = await isGitIntegrationEnabled(workDir);\n if (!enabled) {\n return { committed: false, error: 'Git integration disabled' };\n }\n \n const ledgerPath = join(getTrieDirectory(workDir), 'memory', 'ledger.json');\n \n // Check if ledger has changes\n const { stdout: statusOutput } = await execAsync('git status --porcelain', { cwd: workDir });\n const hasLedgerChanges = statusOutput.includes('ledger.json');\n \n if (!hasLedgerChanges) {\n return { committed: false, error: 'No ledger changes to commit' };\n }\n \n // Stage ledger file\n await execAsync(`git add ${ledgerPath}`, { cwd: workDir });\n \n // Commit with structured message\n const commitMessage = message || 'ledger: append entries';\n await execAsync(\n `git commit -m \"${commitMessage}\"`,\n { cwd: workDir }\n );\n \n // Get commit hash\n const { stdout: hashOutput } = await execAsync('git rev-parse HEAD', { cwd: workDir });\n const commitHash = hashOutput.trim();\n \n return {\n committed: true,\n commitHash\n };\n } catch (error) {\n return {\n committed: false,\n error: error instanceof Error ? error.message : String(error)\n };\n }\n}\n\n/**\n * Enable or disable Git integration\n */\nexport async function setGitIntegration(workDir: string, enabled: boolean): Promise<void> {\n const configPath = join(getTrieDirectory(workDir), 'config.json');\n const fs = await import('fs/promises');\n \n let config: Record<string, any> = {};\n if (existsSync(configPath)) {\n config = JSON.parse(await fs.readFile(configPath, 'utf-8'));\n }\n \n config.gitIntegration = enabled;\n await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');\n}\n\n/**\n * Add .trie/keys/ to .gitignore\n * \n * Signing keys should NOT be committed to git.\n * This ensures they stay local and secure.\n */\nexport async function ensureKeysIgnored(workDir: string): Promise<void> {\n try {\n const gitignorePath = join(workDir, '.gitignore');\n const fs = await import('fs/promises');\n \n let gitignore = '';\n if (existsSync(gitignorePath)) {\n gitignore = await fs.readFile(gitignorePath, 'utf-8');\n }\n \n // Check if already ignored\n if (gitignore.includes('.trie/keys/')) {\n return;\n }\n \n // Add to gitignore\n const addition = '\\n# Trie signing keys (keep secure, do not commit)\\n.trie/keys/\\n';\n await fs.appendFile(gitignorePath, addition, 'utf-8');\n } catch (error) {\n console.error('Failed to update .gitignore:', error);\n }\n}\n"],"mappings":"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","names":["mkdir","readFile","stat","unlink","existsSync","join","existsSync","existsSync","existsSync","exec","promisify","existsSync","join","execAsync","promisify","exec","join","existsSync","join","existsSync","join","mkdir","existsSync","readFile","stat","unlink"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/memory/issue-store.ts","../src/memory/bm25.ts","../src/memory/compactor.ts"],"sourcesContent":["/**\n * Issue Memory Store\n * \n * Working state cache complementary to the immutable ledger.\n * \n * Architecture:\n * - Ledger (.trie/memory/ledger.json) = immutable source of truth\n * - Issue Memory = mutable working state + BM25 search index\n * \n * Issue memory provides:\n * - Fast BM25 semantic search for pattern matching\n * - Mutable state tracking (resolved, open, fixed)\n * - Goal violation metrics and progress tracking\n * - Links back to ledger via ledgerBlockHash\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, 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 { withFileLock } from '../utils/file-lock.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 ledgerBlockHash?: string; // Link to immutable ledger record\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 and link them to the ledger\n * \n * Flow:\n * 1. Append to ledger (immutable source of truth)\n * 2. Cache in issue memory with ledger reference\n * \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 ...(issue.ledgerBlockHash && { ledgerBlockHash: issue.ledgerBlockHash }),\n };\n stored.push(storedIssue);\n }\n\n // 1. Write to ledger (immutable source of truth)\n const ledgerBlock = await appendIssuesToLedger(stored, projectDir);\n \n // 2. Link issues to their ledger block\n if (ledgerBlock) {\n for (const issue of stored) {\n issue.ledgerBlockHash = ledgerBlock.blockHash;\n }\n }\n \n // 3. Cache in issue memory (working state + search index)\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 memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const indexPath = join(memoryDir, 'issues.json');\n \n // Use file locking to prevent concurrent write conflicts\n return withFileLock(indexPath, async () => {\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 saveIssueIndexInternal(index, projectDir);\n return true;\n }, { timeout: 10000 });\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 memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const indexPath = join(memoryDir, 'issues.json');\n \n // Use file locking to prevent concurrent write conflicts\n return withFileLock(indexPath, async () => {\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 saveIssueIndexInternal(index, projectDir);\n }\n \n return { resolved: resolvedCount, stillActive: stillActiveCount };\n }, { timeout: 15000 });\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 memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const indexPath = join(memoryDir, 'issues.json');\n \n // Use file locking to prevent concurrent write conflicts\n let resolvedCount = await withFileLock(indexPath, async () => {\n const index = await loadIssueIndex(projectDir);\n \n const now = new Date().toISOString();\n let count = 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 count++;\n }\n }\n \n if (count > 0) {\n await saveIssueIndexInternal(index, projectDir);\n }\n \n return count;\n }, { timeout: 10000 });\n \n // Always try to resolve nudges in SQL storage, even if issue-store had nothing\n // This handles cases where nudges exist in SQL but not in the issue index\n try {\n const { getStorage } = await import('../storage/tiered-storage.js');\n const storage = getStorage(projectDir);\n await storage.initialize();\n const nudgeResolved = await storage.resolveNudgesForGoalViolation(file, goalDescription, workDir);\n if (nudgeResolved > 0) {\n console.debug(`[IssueStore] Auto-resolved ${nudgeResolved} nudge(s) for fixed goal violation`);\n resolvedCount += nudgeResolved;\n }\n } catch (e) {\n console.debug('[IssueStore] Nudge resolution failed (non-fatal):', e);\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 memoryDir = join(getTrieDirectory(projectDir), 'memory');\n const indexPath = join(memoryDir, 'issues.json');\n \n // Use file locking to prevent concurrent write conflicts\n return withFileLock(indexPath, async () => {\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 saveIssueIndexInternal(remaining, projectDir);\n \n return {\n removed: originalCount - remaining.length,\n remaining: remaining.length,\n strategy,\n };\n }, { timeout: 10000 });\n}\n\n/**\n * Get daily log files (legacy - deprecated)\n * \n * Note: Daily logs are redundant with the ledger.\n * The ledger provides the same information with better guarantees.\n * This function is kept for backward compatibility.\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\n/**\n * Get ledger entry for an issue\n * \n * Issue memory stores working state (resolved, etc.)\n * Ledger stores immutable history (what was detected, when)\n * \n * This helper links them together for full context.\n */\nexport async function getIssueLedgerEntry(\n issue: StoredIssue,\n workDir?: string\n): Promise<{ block: any; entry: any } | null> {\n if (!issue.ledgerBlockHash) return null;\n \n const projectDir = workDir || getWorkingDirectory(undefined, true);\n const { getLedgerBlocks } = await import('./ledger.js');\n const blocks = await getLedgerBlocks(projectDir);\n \n // Find the block this issue is linked to\n const block = blocks.find(b => b.blockHash === issue.ledgerBlockHash);\n if (!block) return null;\n \n // Find the specific entry in that block\n const entry = block.entries.find((e: any) => e.hash === issue.hash);\n if (!entry) return null;\n \n return { block, entry };\n}\n\n// Private helpers\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 const indexPath = join(memoryDir, 'issues.json');\n \n // Use file locking to prevent concurrent write conflicts\n return withFileLock(indexPath, async () => {\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 // Use internal save since lock is already held\n await saveIssueIndexInternal(existing, projectDir);\n return dedupedCount;\n }, { timeout: 15000 });\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 * This is the internal version that doesn't acquire locks.\n * All public functions that call this should acquire locks first.\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 saveIssueIndexInternal(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"],"mappings":"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","names":["mkdir","readFile","existsSync","join","join","mkdir","existsSync","readFile"]}
|