memorix 1.0.1 → 1.0.2
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/CHANGELOG.md +10 -0
- package/dist/cli/index.js +9 -7
- package/dist/cli/index.js.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/store/file-lock.ts","../src/store/persistence.ts","../src/types.ts","../src/config.ts","../src/embedding/fastembed-provider.ts","../src/embedding/transformers-provider.ts","../src/embedding/api-provider.ts","../src/embedding/provider.ts","../src/store/project-affinity.ts","../src/search/intent-detector.ts","../src/project/aliases.ts","../src/llm/provider.ts","../src/llm/quality.ts","../src/store/orama-store.ts","../src/compact/token-budget.ts","../src/memory/entity-extractor.ts","../src/memory/observations.ts","../src/llm/memory-manager.ts","../src/memory/session.ts","../src/memory/retention.ts","../src/skills/engine.ts","../src/skills/mini-skills.ts","../src/memory/consolidation.ts","../src/memory/export-import.ts","../src/dashboard/server.ts","../src/team/registry.ts","../src/team/messages.ts","../src/team/file-locks.ts","../src/team/tasks.ts","../src/team/persistence.ts","../src/hooks/installers/index.ts","../src/index.ts","../src/server.ts","../src/memory/graph.ts","../src/memory/auto-relations.ts","../src/compact/engine.ts","../src/compact/index-format.ts","../src/project/detector.ts","../src/rules/syncer.ts","../src/rules/adapters/cursor.ts","../src/rules/utils.ts","../src/rules/adapters/claude-code.ts","../src/rules/adapters/codex.ts","../src/rules/adapters/windsurf.ts","../src/rules/adapters/antigravity.ts","../src/rules/adapters/copilot.ts","../src/rules/adapters/kiro.ts","../src/rules/adapters/trae.ts","../src/workspace/engine.ts","../src/workspace/mcp-adapters/windsurf.ts","../src/workspace/mcp-adapters/cursor.ts","../src/workspace/mcp-adapters/codex.ts","../src/workspace/mcp-adapters/claude-code.ts","../src/workspace/mcp-adapters/copilot.ts","../src/workspace/mcp-adapters/antigravity.ts","../src/workspace/mcp-adapters/kiro.ts","../src/workspace/mcp-adapters/opencode.ts","../src/workspace/mcp-adapters/trae.ts","../src/workspace/workflow-sync.ts","../src/workspace/sanitizer.ts","../src/workspace/applier.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/**\n * File Lock & Atomic Write Utilities\n *\n * Provides cross-process file locking using .lock files with atomic creation\n * (O_CREAT | O_EXCL), and atomic file writes via temp-file-then-rename.\n *\n * This prevents data corruption when multiple MCP server instances\n * (e.g., Cursor + Windsurf) write to the same project directory simultaneously.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\n/** Lock is considered stale after 10 seconds (process crash recovery) */\nconst LOCK_STALE_MS = 10_000;\n/** Retry interval when waiting for lock */\nconst RETRY_INTERVAL_MS = 50;\n/** Maximum retries before giving up (50ms × 60 = 3 seconds) */\nconst MAX_RETRIES = 60;\n\n/**\n * Acquire a lock file atomically.\n * Uses O_WRONLY | O_CREAT | O_EXCL — fails if file already exists.\n * Handles stale locks from crashed processes.\n */\nexport async function acquireLock(lockPath: string): Promise<void> {\n for (let i = 0; i < MAX_RETRIES; i++) {\n try {\n const fd = await fs.open(lockPath, 'wx');\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\n await fd.close();\n return;\n } catch (err: unknown) {\n const code = err instanceof Error && 'code' in err ? (err as NodeJS.ErrnoException).code : undefined;\n if (code === 'EEXIST' || code === 'EPERM') {\n // Lock exists — check if stale\n try {\n const stat = await fs.stat(lockPath);\n if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n } catch {\n continue; // Lock disappeared — retry immediately\n }\n await new Promise(r => setTimeout(r, RETRY_INTERVAL_MS));\n } else {\n throw err;\n }\n }\n }\n // Last resort: force-remove stale lock and try once more\n await fs.unlink(lockPath).catch(() => {});\n try {\n const fd = await fs.open(lockPath, 'wx');\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\n await fd.close();\n return;\n } catch {\n throw new Error(`Failed to acquire lock: ${lockPath} (timeout after ${MAX_RETRIES * RETRY_INTERVAL_MS}ms)`);\n }\n}\n\n/**\n * Release a lock file.\n */\nexport async function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {});\n}\n\n/**\n * Execute a function while holding a project-level lock.\n * Ensures only one process writes to the project directory at a time.\n *\n * @param projectDir - The project data directory to lock\n * @param fn - The async function to execute while holding the lock\n * @returns The return value of fn\n */\nexport async function withFileLock<T>(projectDir: string, fn: () => Promise<T>): Promise<T> {\n const lockPath = path.join(projectDir, '.memorix.lock');\n await acquireLock(lockPath);\n try {\n return await fn();\n } finally {\n await releaseLock(lockPath);\n }\n}\n\n/**\n * Write a file atomically: write to .tmp, then rename.\n * Prevents partial writes from corrupting data files on crash.\n *\n * On most filesystems, rename() is atomic within the same directory,\n * so readers always see either the old complete file or the new complete file.\n */\nexport async function atomicWriteFile(filePath: string, data: string): Promise<void> {\n const tmpPath = filePath + `.tmp.${process.pid}`;\n await fs.writeFile(tmpPath, data, 'utf-8');\n await fs.rename(tmpPath, filePath);\n}\n","/**\n * Persistence Layer\n *\n * Saves and restores the Orama database to/from disk.\n * Source: @orama/plugin-data-persistence (official Orama plugin)\n *\n * Data is stored in a single FLAT global directory shared across ALL agents and projects:\n * ~/.memorix/data/ (observations.json, graph.jsonl, counter.json, sessions.json)\n *\n * projectId is metadata only — stored inside each observation record,\n * NOT used for directory partitioning. This ensures cross-IDE relay works\n * even when different IDEs detect different projectIds for the same repo.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { atomicWriteFile } from './file-lock.js';\n\n/** Default base data directory — overridable via MEMORIX_DATA_DIR env var */\nconst DEFAULT_DATA_DIR = process.env.MEMORIX_DATA_DIR || path.join(os.homedir(), '.memorix', 'data');\n\n/**\n * Sanitize a projectId for use as a directory name.\n * Used only during migration to locate legacy per-project subdirectories.\n */\nfunction sanitizeProjectId(projectId: string): string {\n return projectId.replace(/\\//g, '--').replace(/[<>:\"|?*\\\\]/g, '_');\n}\n\n/**\n * Get the data directory for Memorix storage.\n *\n * Returns the FLAT global directory (~/.memorix/data/) regardless of projectId.\n * projectId is stored as metadata inside observations, not used for directory partitioning.\n * This ensures all IDEs share the same data directory even if they detect different projectIds.\n *\n * @param _projectId - Ignored for directory purposes (kept for API compat)\n */\nexport async function getProjectDataDir(_projectId: string, baseDir?: string): Promise<string> {\n // Legacy guard — detectProject no longer returns __invalid__ (uses placeholder/ instead)\n // Keep check for safety but should never trigger in normal operation\n const base = baseDir ?? DEFAULT_DATA_DIR;\n await fs.mkdir(base, { recursive: true });\n return base;\n}\n\n/**\n * Get the base data directory (parent of all project dirs).\n */\nexport function getBaseDataDir(baseDir?: string): string {\n return baseDir ?? DEFAULT_DATA_DIR;\n}\n\n/**\n * List all project data directories.\n * Used for cross-project (global) search.\n */\nexport async function listProjectDirs(baseDir?: string): Promise<string[]> {\n const base = baseDir ?? DEFAULT_DATA_DIR;\n try {\n const entries = await fs.readdir(base, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => path.join(base, e.name));\n } catch {\n return [];\n }\n}\n\n/**\n * Migrate legacy per-project subdirectories into the flat base directory.\n *\n * Before v0.9.6, data was stored in per-project subdirectories:\n * ~/.memorix/data/AVIDS2--memorix/observations.json\n * ~/.memorix/data/local--myproject/observations.json\n *\n * This caused data fragmentation when different IDEs detected different projectIds.\n * Now all data lives in ~/.memorix/data/ directly.\n *\n * Migration:\n * 1. Scan all subdirectories under base dir\n * 2. Merge observations from all subdirs into base dir (remap IDs to avoid collision)\n * 3. Merge graph.jsonl (deduplicate entities by name)\n * 4. Move subdirectories to .migrated-subdirs/ backup\n */\nexport async function migrateSubdirsToFlat(baseDir?: string): Promise<boolean> {\n const base = baseDir ?? DEFAULT_DATA_DIR;\n await fs.mkdir(base, { recursive: true });\n\n // Find all subdirectories that contain observations.json\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(base, { withFileTypes: true });\n } catch {\n return false;\n }\n\n const dataDirs = entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => path.join(base, e.name));\n\n if (dataDirs.length === 0) return false;\n\n // Check which subdirs actually have observation data\n const subdirData: Array<{ dir: string; obs: any[]; graph: { entities: any[]; relations: any[] } }> = [];\n for (const dir of dataDirs) {\n const obsPath = path.join(dir, 'observations.json');\n try {\n const data = await fs.readFile(obsPath, 'utf-8');\n const obs = JSON.parse(data);\n if (Array.isArray(obs) && obs.length > 0) {\n // Also try to load graph\n let graph = { entities: [] as any[], relations: [] as any[] };\n try {\n const graphData = await fs.readFile(path.join(dir, 'graph.jsonl'), 'utf-8');\n const lines = graphData.split('\\n').filter((l: string) => l.trim());\n for (const line of lines) {\n const item = JSON.parse(line);\n if (item.type === 'entity') graph.entities.push(item);\n if (item.type === 'relation') graph.relations.push(item);\n }\n } catch { /* no graph */ }\n subdirData.push({ dir, obs, graph });\n }\n } catch { /* no observations */ }\n }\n\n if (subdirData.length === 0) return false;\n\n // Load existing base-level data (if any)\n let baseObs: any[] = [];\n try {\n const data = await fs.readFile(path.join(base, 'observations.json'), 'utf-8');\n baseObs = JSON.parse(data);\n if (!Array.isArray(baseObs)) baseObs = [];\n } catch { /* no existing base data */ }\n\n let baseGraph = { entities: [] as any[], relations: [] as any[] };\n try {\n const graphData = await fs.readFile(path.join(base, 'graph.jsonl'), 'utf-8');\n const lines = graphData.split('\\n').filter((l: string) => l.trim());\n for (const line of lines) {\n const item = JSON.parse(line);\n if (item.type === 'entity') baseGraph.entities.push(item);\n if (item.type === 'relation') baseGraph.relations.push(item);\n }\n } catch { /* no graph */ }\n\n // Merge all observations: collect, sort by createdAt, remap IDs\n const allObs: any[] = [...baseObs];\n for (const { obs } of subdirData) {\n for (const o of obs) {\n // Deduplicate by title+createdAt+projectId (same observation from migration overlap)\n const isDuplicate = allObs.some(\n (existing) => existing.title === o.title && existing.createdAt === o.createdAt,\n );\n if (!isDuplicate) {\n allObs.push(o);\n }\n }\n }\n\n // Sort by createdAt then remap IDs sequentially\n allObs.sort((a, b) => (a.createdAt || '').localeCompare(b.createdAt || ''));\n for (let i = 0; i < allObs.length; i++) {\n allObs[i].id = i + 1;\n }\n\n // Merge graphs (deduplicate entities by name)\n const entityMap = new Map<string, any>();\n for (const e of baseGraph.entities) entityMap.set(e.name, e);\n for (const { graph } of subdirData) {\n for (const e of graph.entities) {\n if (!entityMap.has(e.name)) {\n entityMap.set(e.name, e);\n } else {\n // Merge observations lists\n const existing = entityMap.get(e.name);\n const obsSet = new Set([...(existing.observations || []), ...(e.observations || [])]);\n existing.observations = [...obsSet];\n }\n }\n }\n\n const relationSet = new Set<string>();\n const mergedRelations: any[] = [];\n for (const rel of [...baseGraph.relations, ...subdirData.flatMap((d) => d.graph.relations)]) {\n const key = `${rel.from}|${rel.to}|${rel.relationType}`;\n if (!relationSet.has(key)) {\n relationSet.add(key);\n mergedRelations.push(rel);\n }\n }\n\n // Write merged data to base directory\n await fs.writeFile(path.join(base, 'observations.json'), JSON.stringify(allObs, null, 2), 'utf-8');\n await fs.writeFile(\n path.join(base, 'counter.json'),\n JSON.stringify({ nextId: allObs.length + 1 }),\n 'utf-8',\n );\n\n // Write merged graph\n const graphLines = [\n ...[...entityMap.values()].map((e) => JSON.stringify({ type: 'entity', name: e.name, entityType: e.entityType, observations: e.observations })),\n ...mergedRelations.map((r) => JSON.stringify({ type: 'relation', from: r.from, to: r.to, relationType: r.relationType })),\n ];\n if (graphLines.length > 0) {\n await fs.writeFile(path.join(base, 'graph.jsonl'), graphLines.join('\\n'), 'utf-8');\n }\n\n // Also merge sessions if present\n let allSessions: any[] = [];\n try {\n const data = await fs.readFile(path.join(base, 'sessions.json'), 'utf-8');\n allSessions = JSON.parse(data);\n if (!Array.isArray(allSessions)) allSessions = [];\n } catch { /* no sessions */ }\n for (const { dir } of subdirData) {\n try {\n const data = await fs.readFile(path.join(dir, 'sessions.json'), 'utf-8');\n const sessions = JSON.parse(data);\n if (Array.isArray(sessions)) allSessions.push(...sessions);\n } catch { /* no sessions */ }\n }\n if (allSessions.length > 0) {\n await fs.writeFile(path.join(base, 'sessions.json'), JSON.stringify(allSessions, null, 2), 'utf-8');\n }\n\n // Move subdirectories to backup\n const backupDir = path.join(base, '.migrated-subdirs');\n await fs.mkdir(backupDir, { recursive: true });\n for (const { dir } of subdirData) {\n const dirName = path.basename(dir);\n try {\n await fs.rename(dir, path.join(backupDir, dirName));\n } catch {\n // If rename fails (cross-device), try to just leave it\n // The important thing is the merged data is written\n }\n }\n\n // Also move remaining empty subdirectories\n for (const dir of dataDirs) {\n const dirName = path.basename(dir);\n try {\n await fs.access(dir);\n await fs.rename(dir, path.join(backupDir, dirName));\n } catch { /* already moved or doesn't exist */ }\n }\n\n return true;\n}\n\n/**\n * Get the file path for the Orama database file.\n */\nexport function getDbFilePath(projectDir: string): string {\n return path.join(projectDir, 'memorix.msp');\n}\n\n/**\n * Get the file path for the knowledge graph JSONL file.\n * (MCP-compatible format, same as official Memory Server)\n */\nexport function getGraphFilePath(projectDir: string): string {\n return path.join(projectDir, 'graph.jsonl');\n}\n\n/**\n * Check if a database file exists for the given project.\n */\nexport async function hasExistingData(projectDir: string): Promise<boolean> {\n try {\n await fs.access(getDbFilePath(projectDir));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Save the knowledge graph in JSONL format (MCP-compatible).\n * Each line is a JSON object with type: \"entity\" or \"relation\".\n *\n * Format adopted from MCP Official Memory Server.\n */\nexport async function saveGraphJsonl(\n projectDir: string,\n entities: Array<{ name: string; entityType: string; observations: string[] }>,\n relations: Array<{ from: string; to: string; relationType: string }>,\n): Promise<void> {\n const lines = [\n ...entities.map((e) =>\n JSON.stringify({ type: 'entity', name: e.name, entityType: e.entityType, observations: e.observations }),\n ),\n ...relations.map((r) =>\n JSON.stringify({ type: 'relation', from: r.from, to: r.to, relationType: r.relationType }),\n ),\n ];\n await atomicWriteFile(getGraphFilePath(projectDir), lines.join('\\n'));\n}\n\n/**\n * Load the knowledge graph from JSONL format.\n */\nexport async function loadGraphJsonl(\n projectDir: string,\n): Promise<{\n entities: Array<{ name: string; entityType: string; observations: string[] }>;\n relations: Array<{ from: string; to: string; relationType: string }>;\n}> {\n const filePath = getGraphFilePath(projectDir);\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n const lines = data.split('\\n').filter((line) => line.trim() !== '');\n return lines.reduce(\n (graph, line) => {\n const item = JSON.parse(line);\n if (item.type === 'entity') {\n graph.entities.push({\n name: item.name,\n entityType: item.entityType,\n observations: item.observations,\n });\n }\n if (item.type === 'relation') {\n graph.relations.push({\n from: item.from,\n to: item.to,\n relationType: item.relationType,\n });\n }\n return graph;\n },\n {\n entities: [] as Array<{ name: string; entityType: string; observations: string[] }>,\n relations: [] as Array<{ from: string; to: string; relationType: string }>\n },\n );\n } catch (error) {\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { entities: [], relations: [] };\n }\n throw error;\n }\n}\n\n/**\n * Save observation data as JSON (for Orama restore).\n */\nexport async function saveObservationsJson(\n projectDir: string,\n observations: unknown[],\n): Promise<void> {\n const filePath = path.join(projectDir, 'observations.json');\n await atomicWriteFile(filePath, JSON.stringify(observations, null, 2));\n}\n\n/**\n * Load observation data from JSON.\n */\nexport async function loadObservationsJson(projectDir: string): Promise<unknown[]> {\n const filePath = path.join(projectDir, 'observations.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(data);\n } catch (error) {\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Save the next observation ID counter.\n */\nexport async function saveIdCounter(projectDir: string, nextId: number): Promise<void> {\n const filePath = path.join(projectDir, 'counter.json');\n await atomicWriteFile(filePath, JSON.stringify({ nextId }));\n}\n\n/**\n * Append archived observations to the archive file.\n * Archived observations are moved here by the retention engine.\n */\nexport async function appendArchivedObservations(\n projectDir: string,\n observations: unknown[],\n): Promise<void> {\n const filePath = path.join(projectDir, 'observations.archived.json');\n let existing: unknown[] = [];\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n existing = JSON.parse(data);\n if (!Array.isArray(existing)) existing = [];\n } catch { /* no archive yet */ }\n existing.push(...observations);\n await atomicWriteFile(filePath, JSON.stringify(existing, null, 2));\n}\n\n/**\n * Load archived observations.\n */\nexport async function loadArchivedObservations(projectDir: string): Promise<unknown[]> {\n const filePath = path.join(projectDir, 'observations.archived.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Load the next observation ID counter.\n */\nexport async function loadIdCounter(projectDir: string): Promise<number> {\n const filePath = path.join(projectDir, 'counter.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(data).nextId ?? 1;\n } catch {\n return 1;\n }\n}\n\n/**\n * Save mini-skills data as JSON.\n */\nexport async function saveMiniSkillsJson(\n projectDir: string,\n skills: unknown[],\n): Promise<void> {\n const filePath = path.join(projectDir, 'mini-skills.json');\n await atomicWriteFile(filePath, JSON.stringify(skills, null, 2));\n}\n\n/**\n * Load mini-skills data from JSON.\n */\nexport async function loadMiniSkillsJson(projectDir: string): Promise<unknown[]> {\n const filePath = path.join(projectDir, 'mini-skills.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch (error) {\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Load the mini-skills ID counter.\n */\nexport async function loadMiniSkillsCounter(projectDir: string): Promise<number> {\n const filePath = path.join(projectDir, 'mini-skills-counter.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(data).nextId ?? 1;\n } catch {\n return 1;\n }\n}\n\n/**\n * Save the mini-skills ID counter.\n */\nexport async function saveMiniSkillsCounter(projectDir: string, nextId: number): Promise<void> {\n const filePath = path.join(projectDir, 'mini-skills-counter.json');\n await atomicWriteFile(filePath, JSON.stringify({ nextId }));\n}\n\n/**\n * Save sessions data as JSON.\n */\nexport async function saveSessionsJson(\n projectDir: string,\n sessions: unknown[],\n): Promise<void> {\n const filePath = path.join(projectDir, 'sessions.json');\n await atomicWriteFile(filePath, JSON.stringify(sessions, null, 2));\n}\n\n/**\n * Load sessions data from JSON.\n */\nexport async function loadSessionsJson(projectDir: string): Promise<unknown[]> {\n const filePath = path.join(projectDir, 'sessions.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(data);\n } catch (error) {\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n return [];\n }\n throw error;\n }\n}\n","/**\n * Memorix Core Types\n *\n * Data model sources:\n * - Entity/Relation/KnowledgeGraph: MCP Official Memory Server (v0.6.3)\n * - Observation/ObservationType: claude-mem Progressive Disclosure\n * - UnifiedRule/RuleSource: Memorix original (rules sync)\n *\n * Designed for extensibility: new agent formats (Kiro, Copilot, Antigravity)\n * can be added by extending RuleSource and adding format adapters.\n */\n\n// ============================================================\n// Knowledge Graph (adopted from MCP Official Memory Server)\n// ============================================================\n\n/** A node in the knowledge graph representing a concept, component, or config */\nexport interface Entity {\n name: string;\n entityType: string;\n observations: string[];\n}\n\n/** A directed edge between two entities */\nexport interface Relation {\n from: string;\n to: string;\n relationType: string;\n}\n\n/** The complete knowledge graph */\nexport interface KnowledgeGraph {\n entities: Entity[];\n relations: Relation[];\n}\n\n// ============================================================\n// Observation (adopted from claude-mem Progressive Disclosure)\n// ============================================================\n\n/**\n * Observation type classification using claude-mem's icon-based legend system.\n *\n * Icon mapping:\n * 🎯 session-request — User's original goal\n * 🔴 gotcha — Critical pitfall / trap\n * 🟡 problem-solution — Bug fix or workaround\n * 🔵 how-it-works — Technical explanation\n * 🟢 what-changed — Code/architecture change\n * 🟣 discovery — New learning or insight\n * 🟠 why-it-exists — Design rationale\n * 🟤 decision — Architecture decision\n * ⚖️ trade-off — Deliberate compromise\n */\nexport type ObservationType =\n | 'session-request'\n | 'gotcha'\n | 'problem-solution'\n | 'how-it-works'\n | 'what-changed'\n | 'discovery'\n | 'why-it-exists'\n | 'decision'\n | 'trade-off';\n\n/** Map from ObservationType to display icon */\nexport const OBSERVATION_ICONS: Record<ObservationType, string> = {\n 'session-request': '🎯',\n 'gotcha': '🔴',\n 'problem-solution': '🟡',\n 'how-it-works': '🔵',\n 'what-changed': '🟢',\n 'discovery': '🟣',\n 'why-it-exists': '🟠',\n 'decision': '🟤',\n 'trade-off': '⚖️',\n};\n\n/** Observation lifecycle status */\nexport type ObservationStatus = 'active' | 'resolved' | 'archived';\n\n/** Progress tracking for task/feature observations */\nexport interface ProgressInfo {\n feature: string;\n status: 'in-progress' | 'completed' | 'blocked';\n completion?: number;\n}\n\n/** A rich observation record attached to an entity */\nexport interface Observation {\n id: number;\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts: string[];\n filesModified: string[];\n concepts: string[];\n tokens: number;\n createdAt: string;\n updatedAt?: string;\n projectId: string;\n /** Whether the observation contains causal language (because, due to, etc.) */\n hasCausalLanguage?: boolean;\n /** Optional topic key for upsert — same project+topicKey updates existing observation */\n topicKey?: string;\n /** How many times this observation was revised via topic key upsert (starts at 1) */\n revisionCount?: number;\n /** Session ID this observation belongs to */\n sessionId?: string;\n /** Lifecycle status: active (default) → resolved → archived */\n status?: ObservationStatus;\n /** ID of the observation that superseded this one (set when auto-resolved by topicKey upsert) */\n supersededBy?: number;\n /** Progress tracking for task/feature observations */\n progress?: ProgressInfo;\n}\n\n// ============================================================\n// Session Lifecycle (inspired by Engram's session management)\n// ============================================================\n\n/** A coding session tracked by Memorix */\nexport interface Session {\n id: string;\n projectId: string;\n startedAt: string;\n endedAt?: string;\n summary?: string;\n status: 'active' | 'completed';\n /** Agent/IDE that started this session */\n agent?: string;\n}\n\n// ============================================================\n// Compact Engine (adopted from claude-mem 3-layer workflow)\n// ============================================================\n\n/** L1 index entry — lightweight, ~50-100 tokens per result */\nexport interface IndexEntry {\n id: number;\n time: string;\n type: ObservationType;\n icon: string;\n title: string;\n tokens: number;\n /** Relevance score from search (time-decayed). Used by compact engine. */\n score?: number;\n}\n\n/** L2 timeline context — observations around an anchor */\nexport interface TimelineContext {\n anchorId: number;\n anchorEntry: IndexEntry | null;\n before: IndexEntry[];\n after: IndexEntry[];\n}\n\n/** Search options for the compact engine */\nexport interface SearchOptions {\n query: string;\n limit?: number;\n type?: ObservationType;\n projectId?: string;\n since?: string;\n until?: string;\n /** Token budget — trim results to fit within this many tokens (0 = unlimited) */\n maxTokens?: number;\n /** Filter by observation status. Default: 'active' (only show active memories) */\n status?: ObservationStatus | 'all';\n}\n\n/** Topic key family heuristics for suggesting stable topic keys */\nexport const TOPIC_KEY_FAMILIES: Record<string, string[]> = {\n 'architecture': ['architecture', 'design', 'adr', 'structure', 'pattern'],\n 'bug': ['bugfix', 'fix', 'error', 'regression', 'crash', 'problem-solution'],\n 'decision': ['decision', 'trade-off', 'choice', 'strategy'],\n 'config': ['config', 'setup', 'env', 'environment', 'deployment'],\n 'discovery': ['discovery', 'learning', 'insight', 'gotcha'],\n 'pattern': ['pattern', 'convention', 'standard', 'best-practice'],\n};\n\n// ============================================================\n// Orama Document Schema\n// ============================================================\n\n/** The document shape stored in Orama */\nexport interface MemorixDocument {\n id: string;\n observationId: number;\n entityName: string;\n type: string;\n title: string;\n narrative: string;\n facts: string;\n filesModified: string;\n concepts: string;\n tokens: number;\n createdAt: string;\n projectId: string;\n /** Number of times this observation was returned in search results */\n accessCount: number;\n /** ISO timestamp of last access via search/detail */\n lastAccessedAt: string;\n /** Lifecycle status: active, resolved, archived */\n status: string;\n}\n\n// ============================================================\n// Rules System (Memorix original — extensible for new agents)\n// ============================================================\n\n/**\n * Supported agent/IDE rule sources.\n * All 7 major AI IDEs are supported.\n */\nexport type RuleSource =\n | 'cursor'\n | 'claude-code'\n | 'codex'\n | 'windsurf'\n | 'antigravity'\n | 'copilot'\n | 'kiro'\n | 'trae'\n | 'memorix';\n\n/** A parsed rule in the unified intermediate representation */\nexport interface UnifiedRule {\n id: string;\n content: string;\n description?: string;\n source: RuleSource;\n scope: 'global' | 'project' | 'path-specific';\n paths?: string[];\n alwaysApply?: boolean;\n priority: number;\n hash: string;\n}\n\n/**\n * Format adapter interface — implement this for each agent/IDE.\n * Adding a new agent (e.g., Kiro) only requires implementing this interface.\n */\nexport interface RuleFormatAdapter {\n /** Unique identifier for this agent format */\n readonly source: RuleSource;\n\n /** File paths/globs this adapter can parse */\n readonly filePatterns: string[];\n\n /** Parse rule files into unified representation */\n parse(filePath: string, content: string): UnifiedRule[];\n\n /** Generate rule file content from unified representation */\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[];\n}\n\n// ============================================================\n// Project Identity\n// ============================================================\n\nexport interface ProjectInfo {\n id: string;\n name: string;\n gitRemote?: string;\n rootPath: string;\n}\n\n// ============================================================\n// Memorix Server Configuration\n// ============================================================\n\nexport interface MemorixConfig {\n dataDir: string;\n projectId: string;\n projectName: string;\n enableEmbeddings: boolean;\n enableRulesSync: boolean;\n watchRuleFiles: boolean;\n}\n\nexport const DEFAULT_CONFIG: Partial<MemorixConfig> = {\n enableEmbeddings: false,\n enableRulesSync: false,\n watchRuleFiles: false,\n};\n\n// ============================================================\n// Workspace Sync — Cross-Agent workspace migration\n// ============================================================\n\n/** Supported agent targets for workspace sync */\nexport type AgentTarget = 'windsurf' | 'cursor' | 'claude-code' | 'codex' | 'copilot' | 'antigravity' | 'kiro' | 'opencode' | 'trae';\n\n/** A unified MCP server entry across all agent config formats */\nexport interface MCPServerEntry {\n name: string;\n /** Command for stdio transport */\n command: string;\n /** Args for stdio transport */\n args: string[];\n /** Environment variables */\n env?: Record<string, string> | null;\n /** URL for HTTP/SSE transport (Codex uses `url`, Windsurf uses `serverUrl`) */\n url?: string;\n /** HTTP headers (Windsurf uses `headers` for HTTP transport) */\n headers?: Record<string, string>;\n /** Whether this server is disabled */\n disabled?: boolean;\n}\n\n/** Unified workflow entry */\nexport interface WorkflowEntry {\n name: string;\n description: string;\n content: string;\n source: AgentTarget;\n filePath: string;\n}\n\n/** A skill folder discovered from an agent's skills directory */\nexport interface SkillEntry {\n name: string;\n description: string;\n sourcePath: string;\n sourceAgent: AgentTarget;\n}\n\n/** Conflict when two agents have a skill with the same folder name */\nexport interface SkillConflict {\n name: string;\n kept: SkillEntry;\n skipped: SkillEntry;\n}\n\n/** Result of a workspace sync operation */\nexport interface WorkspaceSyncResult {\n mcpServers: {\n scanned: MCPServerEntry[];\n generated: { filePath: string; content: string }[];\n };\n workflows: {\n scanned: WorkflowEntry[];\n generated: { filePath: string; content: string }[];\n };\n rules: {\n scanned: number;\n generated: number;\n };\n skills: {\n scanned: SkillEntry[];\n conflicts: SkillConflict[];\n copied: string[];\n skipped: string[];\n };\n}\n\n// ============================================================\n// Mini-Skills — Promoted memories that never decay\n// ============================================================\n\n/** A mini-skill promoted from one or more observations */\nexport interface MiniSkill {\n id: number;\n /** Observation IDs this mini-skill was derived from */\n sourceObservationIds: number[];\n /** Entity the source observations belong to */\n sourceEntity: string;\n /** Short title for the skill */\n title: string;\n /** What the agent should do (imperative instruction) */\n instruction: string;\n /** When this skill should be applied (scenario description) */\n trigger: string;\n /** Key facts extracted from source observations */\n facts: string[];\n /** Project this skill belongs to */\n projectId: string;\n /** ISO timestamp */\n createdAt: string;\n /** How many times this skill was injected in session_start */\n usedCount: number;\n /** Classification tags */\n tags: string[];\n}\n\n/** MCP config format adapter interface */\nexport interface MCPConfigAdapter {\n readonly source: AgentTarget;\n /** Parse MCP server entries from a config file */\n parse(content: string): MCPServerEntry[];\n /** Generate config file content from MCP server entries */\n generate(servers: MCPServerEntry[]): string;\n /** Get the default config file path for this agent */\n getConfigPath(projectRoot?: string): string;\n}\n","/**\n * Unified Configuration Reader\n *\n * Priority chain (highest wins):\n * 1. Environment variables (from MCP JSON `env` field or system env)\n * 2. ~/.memorix/config.json (written by `memorix configure` TUI)\n * 3. Hardcoded defaults\n *\n * This ensures `memorix configure` actually takes effect at runtime,\n * while env vars can still override for advanced users.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface MemorixConfig {\n llm?: {\n provider?: string;\n apiKey?: string;\n model?: string;\n baseUrl?: string;\n };\n embedding?: string;\n embeddingApi?: {\n apiKey?: string;\n baseUrl?: string;\n model?: string;\n dimensions?: number;\n };\n}\n\n// ─── Singleton ───────────────────────────────────────────────────────\n\nlet cachedConfig: MemorixConfig | null = null;\n\n/**\n * Load config from ~/.memorix/config.json.\n * Cached after first load. Returns empty object on failure.\n */\nexport function loadFileConfig(): MemorixConfig {\n if (cachedConfig !== null) return cachedConfig;\n\n const configPath = join(homedir(), '.memorix', 'config.json');\n try {\n if (existsSync(configPath)) {\n cachedConfig = JSON.parse(readFileSync(configPath, 'utf-8'));\n return cachedConfig!;\n }\n } catch {\n // Corrupt or unreadable — ignore\n }\n cachedConfig = {};\n return cachedConfig;\n}\n\n/**\n * Reset cached config (for testing).\n */\nexport function resetConfigCache(): void {\n cachedConfig = null;\n}\n\n// ─── Resolved Getters (env > config.json > default) ──────────────────\n\n/** LLM API key: MEMORIX-specific env > config.json > generic env fallback */\nexport function getLLMApiKey(): string | undefined {\n return (\n process.env.MEMORIX_LLM_API_KEY ||\n loadFileConfig().llm?.apiKey ||\n process.env.OPENAI_API_KEY ||\n process.env.ANTHROPIC_API_KEY ||\n process.env.OPENROUTER_API_KEY ||\n undefined\n );\n}\n\n/** LLM provider: env > config.json > auto-detect */\nexport function getLLMProvider(): string {\n if (process.env.MEMORIX_LLM_PROVIDER) return process.env.MEMORIX_LLM_PROVIDER;\n const cfg = loadFileConfig();\n if (cfg.llm?.provider) return cfg.llm.provider;\n // Auto-detect from env var names\n if (process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) return 'anthropic';\n if (process.env.OPENROUTER_API_KEY && !process.env.OPENAI_API_KEY) return 'openrouter';\n return 'openai';\n}\n\n/** LLM model: env > config.json > provider default */\nexport function getLLMModel(providerDefault: string): string {\n return process.env.MEMORIX_LLM_MODEL || loadFileConfig().llm?.model || providerDefault;\n}\n\n/** LLM base URL: env > config.json > provider default */\nexport function getLLMBaseUrl(providerDefault: string): string {\n return process.env.MEMORIX_LLM_BASE_URL || loadFileConfig().llm?.baseUrl || providerDefault;\n}\n\n/** Embedding mode: env > config.json > 'off' */\nexport function getEmbeddingMode(): 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' {\n const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();\n if (env === 'fastembed' || env === 'transformers' || env === 'api' || env === 'auto') return env;\n const cfg = loadFileConfig();\n if (cfg.embedding === 'fastembed' || cfg.embedding === 'transformers' || cfg.embedding === 'api' || cfg.embedding === 'auto') {\n return cfg.embedding;\n }\n return 'off';\n}\n\n/** Embedding API key: env > config.json > LLM key fallback */\nexport function getEmbeddingApiKey(): string | undefined {\n return (\n process.env.MEMORIX_EMBEDDING_API_KEY ||\n loadFileConfig().embeddingApi?.apiKey ||\n process.env.MEMORIX_LLM_API_KEY ||\n loadFileConfig().llm?.apiKey ||\n process.env.OPENAI_API_KEY ||\n undefined\n );\n}\n\n/** Embedding base URL: env > config.json > LLM URL fallback */\nexport function getEmbeddingBaseUrl(): string {\n return (\n process.env.MEMORIX_EMBEDDING_BASE_URL ||\n loadFileConfig().embeddingApi?.baseUrl ||\n process.env.MEMORIX_LLM_BASE_URL ||\n loadFileConfig().llm?.baseUrl ||\n 'https://api.openai.com/v1'\n );\n}\n\n/** Embedding model: env > config.json > default */\nexport function getEmbeddingModel(): string {\n return (\n process.env.MEMORIX_EMBEDDING_MODEL ||\n loadFileConfig().embeddingApi?.model ||\n 'text-embedding-3-small'\n );\n}\n\n/** Embedding dimensions override: env > config.json > null (auto-detect) */\nexport function getEmbeddingDimensions(): number | null {\n const envDim = process.env.MEMORIX_EMBEDDING_DIMENSIONS;\n if (envDim) return parseInt(envDim, 10);\n const cfgDim = loadFileConfig().embeddingApi?.dimensions;\n if (cfgDim) return cfgDim;\n return null;\n}\n","/**\n * FastEmbed Provider\n *\n * Local ONNX-based embedding using fastembed (Qdrant).\n * Model: BAAI/bge-small-en-v1.5 (384 dimensions, ~30MB)\n *\n * This is an optional dependency — if fastembed is not installed,\n * the provider module gracefully falls back to fulltext-only search.\n *\n * Persistent disk cache: embeddings are saved to ~/.memorix/data/.embedding-cache.json\n * so server restarts don't need to regenerate them (saves minutes of CPU on 500+ obs).\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { EmbeddingProvider } from './provider.js';\n\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-cache.json');\n\n// In-memory cache keyed by text hash → embedding\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 5000;\nlet diskCacheDirty = false;\n\nfunction textHash(text: string): string {\n return createHash('sha256').update(text).digest('hex').slice(0, 16);\n}\n\nasync function loadDiskCache(): Promise<void> {\n try {\n const raw = await readFile(CACHE_FILE, 'utf-8');\n const entries: [string, number[]][] = JSON.parse(raw);\n for (const [k, v] of entries) cache.set(k, v);\n console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);\n } catch {\n // No cache file or corrupt — start fresh\n }\n}\n\nasync function saveDiskCache(): Promise<void> {\n if (!diskCacheDirty) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const entries = Array.from(cache.entries());\n await writeFile(CACHE_FILE, JSON.stringify(entries));\n diskCacheDirty = false;\n } catch {\n // Ignore write errors — cache is an optimization, not critical\n }\n}\n\nexport class FastEmbedProvider implements EmbeddingProvider {\n readonly name = 'fastembed-bge-small';\n readonly dimensions = 384;\n\n private model: { embed: (docs: string[], batchSize?: number) => AsyncGenerator<number[][]>; queryEmbed: (query: string) => Promise<number[]> };\n\n private constructor(model: FastEmbedProvider['model']) {\n this.model = model;\n }\n\n /**\n * Initialize the FastEmbed provider.\n * Downloads model on first use (~30MB), cached locally after.\n * Loads persistent embedding cache from disk.\n */\n static async create(): Promise<FastEmbedProvider> {\n // Dynamic import — throws if fastembed is not installed\n const { EmbeddingModel, FlagEmbedding } = await import('fastembed');\n const model = await FlagEmbedding.init({\n model: EmbeddingModel.BGESmallENV15,\n });\n // Load disk cache before returning — subsequent embedBatch calls will hit cache\n await loadDiskCache();\n return new FastEmbedProvider(model);\n }\n\n async embed(text: string): Promise<number[]> {\n const hash = textHash(text);\n const cached = cache.get(hash);\n if (cached) return cached;\n\n const raw = await this.model.queryEmbed(text);\n // Ensure plain number[] (fastembed may return Float32Array)\n const result = Array.from(raw) as number[];\n if (result.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);\n }\n this.cacheSet(hash, result);\n return result;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n // Check cache for each text (by hash)\n for (let i = 0; i < texts.length; i++) {\n const hash = textHash(texts[i]);\n const cached = cache.get(hash);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(texts[i]);\n }\n }\n\n // Batch embed uncached texts\n if (uncachedTexts.length > 0) {\n console.error(`[memorix] Embedding ${uncachedTexts.length}/${texts.length} uncached texts (${texts.length - uncachedTexts.length} from cache)`);\n let batchIdx = 0;\n for await (const batch of this.model.embed(uncachedTexts, 64)) {\n for (const vec of batch) {\n const originalIdx = uncachedIndices[batchIdx];\n const plain = Array.from(vec) as number[];\n results[originalIdx] = plain;\n this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);\n batchIdx++;\n }\n }\n // Persist cache to disk after batch operations\n await saveDiskCache();\n }\n\n return results;\n }\n\n private cacheSet(hash: string, value: number[]): void {\n // Evict oldest entries if cache is full\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(hash, value);\n diskCacheDirty = true;\n }\n}\n","/**\r\n * Transformers.js Provider\r\n *\r\n * Pure JavaScript embedding using @huggingface/transformers (HuggingFace).\r\n * Model: Xenova/all-MiniLM-L6-v2 (384 dimensions, ~22MB quantized)\r\n *\r\n * Key advantages over fastembed:\r\n * - No native ONNX binding required (pure JS / WASM)\r\n * - Works out-of-the-box on Windows, macOS, Linux\r\n * - Supports quantized models (q8, q4) for smaller footprint\r\n *\r\n * This is an optional dependency — if @huggingface/transformers is not\r\n * installed, the provider module gracefully falls back to the next option.\r\n *\r\n * Inspired by Mem0's multi-provider embedding architecture.\r\n */\r\n\r\nimport type { EmbeddingProvider } from './provider.js';\r\n\r\n// In-memory LRU cache\r\nconst cache = new Map<string, number[]>();\r\nconst MAX_CACHE_SIZE = 5000;\r\n\r\nexport class TransformersProvider implements EmbeddingProvider {\r\n readonly name = 'transformers-minilm';\r\n readonly dimensions = 384;\r\n\r\n private extractor: any; // Pipeline instance\r\n\r\n private constructor(extractor: any) {\r\n this.extractor = extractor;\r\n }\r\n\r\n /**\r\n * Initialize the Transformers.js provider.\r\n * Downloads model on first use (~22MB quantized), cached locally after.\r\n */\r\n static async create(): Promise<TransformersProvider> {\r\n // Dynamic import — throws if @huggingface/transformers is not installed\r\n const { pipeline } = await import('@huggingface/transformers');\r\n const extractor = await pipeline(\r\n 'feature-extraction',\r\n 'Xenova/all-MiniLM-L6-v2',\r\n { dtype: 'q8' }, // Quantized for small footprint\r\n );\r\n return new TransformersProvider(extractor);\r\n }\r\n\r\n async embed(text: string): Promise<number[]> {\r\n // Check cache first\r\n const cached = cache.get(text);\r\n if (cached) return cached;\r\n\r\n const output = await this.extractor(text, {\r\n pooling: 'mean',\r\n normalize: true,\r\n });\r\n\r\n // output.tolist() returns [[...384 floats]]\r\n const result: number[] = Array.from(output.tolist()[0]);\r\n if (result.length !== this.dimensions) {\r\n throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);\r\n }\r\n\r\n this.cacheSet(text, result);\r\n return result;\r\n }\r\n\r\n async embedBatch(texts: string[]): Promise<number[][]> {\r\n const results: number[][] = new Array(texts.length);\r\n const uncachedIndices: number[] = [];\r\n const uncachedTexts: string[] = [];\r\n\r\n // Check cache for each text\r\n for (let i = 0; i < texts.length; i++) {\r\n const cached = cache.get(texts[i]);\r\n if (cached) {\r\n results[i] = cached;\r\n } else {\r\n uncachedIndices.push(i);\r\n uncachedTexts.push(texts[i]);\r\n }\r\n }\r\n\r\n // Batch embed uncached texts\r\n if (uncachedTexts.length > 0) {\r\n const output = await this.extractor(uncachedTexts, {\r\n pooling: 'mean',\r\n normalize: true,\r\n });\r\n const allVecs: number[][] = output.tolist();\r\n\r\n for (let i = 0; i < allVecs.length; i++) {\r\n const vec = Array.from(allVecs[i]) as number[];\r\n const originalIdx = uncachedIndices[i];\r\n results[originalIdx] = vec;\r\n this.cacheSet(uncachedTexts[i], vec);\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n private cacheSet(key: string, value: number[]): void {\r\n if (cache.size >= MAX_CACHE_SIZE) {\r\n const firstKey = cache.keys().next().value;\r\n if (firstKey !== undefined) cache.delete(firstKey);\r\n }\r\n cache.set(key, value);\r\n }\r\n}\r\n","/**\n * API Embedding Provider\n *\n * Remote embedding via any OpenAI-compatible /v1/embeddings endpoint.\n * Works with: OpenAI, Qwen (DashScope), Cohere, 中转站/反代, Ollama, etc.\n *\n * Advantages over local providers:\n * - Zero local resource usage (no 300-500MB RAM)\n * - Access to larger, higher-quality models (1024-3072 dimensions)\n * - Works on any machine without native bindings\n *\n * Performance advantages vs competitors (mcp-memory-service, claude-mem, Mem0):\n * ┌────────────────────────────┬──────────────┬──────────────────────────┐\n * │ Feature │ Competitors │ Memorix │\n * ├────────────────────────────┼──────────────┼──────────────────────────┤\n * │ Embedding cache │ None │ 10K LRU + disk persist │\n * │ Batch API calls │ 1-by-1 │ Up to 2048 per request │\n * │ Cache hit → API bypass │ No │ SHA-256 dedup, 0ms │\n * │ Retry with backoff │ Crash/skip │ Exponential + Retry-After│\n * │ Text normalization │ No │ Whitespace + truncation │\n * │ Debounced disk writes │ N/A │ 5s coalesce window │\n * │ Concurrent batch chunks │ Sequential │ Parallel (4 concurrent) │\n * │ Dimension shortening │ Hardcoded │ Runtime configurable │\n * │ External dependency │ Chroma/SQLite│ Zero (native fetch) │\n * │ Input token waste │ Full text │ Truncated to 8191 tokens │\n * └────────────────────────────┴──────────────┴──────────────────────────┘\n *\n * Environment variables:\n * MEMORIX_EMBEDDING=api — enable this provider\n * MEMORIX_EMBEDDING_API_KEY — API key (fallback: MEMORIX_LLM_API_KEY → OPENAI_API_KEY)\n * MEMORIX_EMBEDDING_BASE_URL — base URL (fallback: MEMORIX_LLM_BASE_URL → https://api.openai.com/v1)\n * MEMORIX_EMBEDDING_MODEL — model name (default: text-embedding-3-small)\n * MEMORIX_EMBEDDING_DIMENSIONS — optional dimension override (e.g., 512 for cost savings)\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { EmbeddingProvider } from './provider.js';\n\n// ─── Cache Configuration ─────────────────────────────────────────────\n\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-api-cache.json');\n\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 10000;\nlet diskCacheDirty = false;\nlet diskSaveTimer: ReturnType<typeof setTimeout> | null = null;\n\n/** Max input text length (chars) — prevent token waste on huge texts */\nconst MAX_INPUT_CHARS = 32000;\n\n/** Max concurrent batch chunks to process in parallel */\nconst MAX_CONCURRENCY = 4;\n\n/** Debounce window for disk cache writes (ms) */\nconst DISK_SAVE_DEBOUNCE_MS = 5000;\n\n// ─── API Configuration ───────────────────────────────────────────────\n\n/** Max texts per API batch (OpenAI limit: 2048) */\nconst MAX_BATCH_SIZE = 2048;\n\n/** Max retries for transient failures */\nconst MAX_RETRIES = 3;\n\n/** Base delay for exponential backoff (ms) */\nconst BASE_DELAY_MS = 500;\n\n// ─── Cache Helpers ───────────────────────────────────────────────────\n\n/**\n * Normalize text for consistent cache hits.\n * Collapses whitespace and trims — \"hello world\" and \"hello world\" get same embedding.\n */\nfunction normalizeText(text: string): string {\n return text.replace(/\\s+/g, ' ').trim().slice(0, MAX_INPUT_CHARS);\n}\n\nfunction textHash(text: string): string {\n return createHash('sha256').update(text).digest('hex').slice(0, 16);\n}\n\nasync function loadDiskCache(): Promise<void> {\n try {\n const raw = await readFile(CACHE_FILE, 'utf-8');\n const entries: [string, number[]][] = JSON.parse(raw);\n for (const [k, v] of entries) cache.set(k, v);\n console.error(`[memorix] Loaded ${entries.length} cached API embeddings from disk`);\n } catch {\n // No cache file or corrupt — start fresh\n }\n}\n\nasync function saveDiskCacheNow(): Promise<void> {\n if (!diskCacheDirty) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const entries = Array.from(cache.entries());\n await writeFile(CACHE_FILE, JSON.stringify(entries));\n diskCacheDirty = false;\n } catch {\n // Ignore write errors — cache is optimization, not critical\n }\n}\n\n/**\n * Debounced disk cache save — coalesces rapid writes into one 5s-delayed write.\n * Competitors write on every single embed call; we batch for I/O efficiency.\n */\nfunction scheduleDiskSave(): void {\n if (diskSaveTimer) clearTimeout(diskSaveTimer);\n diskSaveTimer = setTimeout(() => {\n saveDiskCacheNow().catch(() => {});\n diskSaveTimer = null;\n }, DISK_SAVE_DEBOUNCE_MS);\n}\n\nfunction cacheSet(hash: string, value: number[]): void {\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(hash, value);\n diskCacheDirty = true;\n}\n\n// ─── API Types ───────────────────────────────────────────────────────\n\ninterface EmbeddingAPIResponse {\n object: string;\n data: Array<{\n object: string;\n index: number;\n embedding: number[];\n }>;\n model: string;\n usage?: {\n prompt_tokens: number;\n total_tokens: number;\n };\n}\n\ninterface APIEmbeddingConfig {\n apiKey: string;\n baseUrl: string;\n model: string;\n requestedDimensions: number | null;\n}\n\n// ─── Provider Implementation ─────────────────────────────────────────\n\nexport class APIEmbeddingProvider implements EmbeddingProvider {\n readonly name: string;\n readonly dimensions: number;\n\n private config: APIEmbeddingConfig;\n private totalTokensUsed = 0;\n private totalApiCalls = 0;\n\n private constructor(config: APIEmbeddingConfig, detectedDimensions: number) {\n this.config = config;\n this.dimensions = detectedDimensions;\n this.name = `api-${config.model.replace(/\\//g, '-')}`;\n }\n\n /**\n * Initialize the API embedding provider.\n * Probes the API with a test embedding to detect dimensions.\n */\n static async create(): Promise<APIEmbeddingProvider> {\n const config = APIEmbeddingProvider.resolveConfig();\n\n // Load disk cache\n await loadDiskCache();\n\n // Probe API to detect dimensions\n const probeDimensions = await APIEmbeddingProvider.probeAPI(config);\n\n console.error(`[memorix] API embedding: ${config.model} @ ${config.baseUrl} (${probeDimensions}d)`);\n if (config.requestedDimensions) {\n console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);\n }\n\n return new APIEmbeddingProvider(config, probeDimensions);\n }\n\n /**\n * Resolve configuration from environment variables.\n * Falls back to LLM config → OpenAI defaults.\n */\n private static resolveConfig(): APIEmbeddingConfig {\n // Unified config: env vars > config.json > defaults\n let apiKey: string | undefined;\n let baseUrl: string;\n let model: string;\n let requestedDimensions: number | null;\n\n try {\n const cfg = require('../config.js');\n apiKey = cfg.getEmbeddingApiKey();\n baseUrl = cfg.getEmbeddingBaseUrl();\n model = cfg.getEmbeddingModel();\n requestedDimensions = cfg.getEmbeddingDimensions();\n } catch {\n // Fallback: direct env var reading\n apiKey =\n process.env.MEMORIX_EMBEDDING_API_KEY ||\n process.env.MEMORIX_LLM_API_KEY ||\n process.env.OPENAI_API_KEY;\n baseUrl =\n process.env.MEMORIX_EMBEDDING_BASE_URL ||\n process.env.MEMORIX_LLM_BASE_URL ||\n 'https://api.openai.com/v1';\n model = process.env.MEMORIX_EMBEDDING_MODEL || 'text-embedding-3-small';\n const dimStr = process.env.MEMORIX_EMBEDDING_DIMENSIONS;\n requestedDimensions = dimStr ? parseInt(dimStr, 10) : null;\n }\n\n if (!apiKey) {\n throw new Error(\n 'No API key for embedding. Set MEMORIX_EMBEDDING_API_KEY, MEMORIX_LLM_API_KEY, or OPENAI_API_KEY, or run `memorix configure`.',\n );\n }\n\n baseUrl = baseUrl.replace(/\\/+$/, ''); // Strip trailing slash\n\n return { apiKey, baseUrl, model, requestedDimensions };\n }\n\n /**\n * Probe API with a test text to detect actual output dimensions.\n */\n private static async probeAPI(config: APIEmbeddingConfig): Promise<number> {\n const body: Record<string, unknown> = {\n model: config.model,\n input: 'dimension probe',\n };\n if (config.requestedDimensions) {\n body.dimensions = config.requestedDimensions;\n }\n\n const response = await fetchWithRetry(\n `${config.baseUrl}/embeddings`,\n config.apiKey,\n body,\n );\n\n if (response.data.length === 0 || !response.data[0].embedding) {\n throw new Error('API probe returned no embeddings — check model name and API key');\n }\n\n return response.data[0].embedding.length;\n }\n\n async embed(text: string): Promise<number[]> {\n const normalized = normalizeText(text);\n const hash = textHash(normalized);\n const cached = cache.get(hash);\n if (cached) return cached;\n\n const body: Record<string, unknown> = {\n model: this.config.model,\n input: normalized,\n };\n if (this.config.requestedDimensions) {\n body.dimensions = this.config.requestedDimensions;\n }\n\n const response = await fetchWithRetry(\n `${this.config.baseUrl}/embeddings`,\n this.config.apiKey,\n body,\n );\n\n const embedding = response.data[0].embedding;\n if (embedding.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d — dimension mismatch`);\n }\n\n this.trackUsage(response);\n cacheSet(hash, embedding);\n scheduleDiskSave();\n return embedding;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const normalizedTexts = texts.map(normalizeText);\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n // Check cache for each text\n for (let i = 0; i < normalizedTexts.length; i++) {\n const hash = textHash(normalizedTexts[i]);\n const cached = cache.get(hash);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(normalizedTexts[i]);\n }\n }\n\n if (uncachedTexts.length === 0) return results;\n\n const cacheHitRate = ((texts.length - uncachedTexts.length) / texts.length * 100).toFixed(1);\n console.error(\n `[memorix] API embedding ${uncachedTexts.length}/${texts.length} texts (cache hit: ${cacheHitRate}%)`,\n );\n\n // Split into chunks of MAX_BATCH_SIZE, then process up to MAX_CONCURRENCY in parallel\n const chunks: { texts: string[]; indices: number[] }[] = [];\n for (let batchStart = 0; batchStart < uncachedTexts.length; batchStart += MAX_BATCH_SIZE) {\n chunks.push({\n texts: uncachedTexts.slice(batchStart, batchStart + MAX_BATCH_SIZE),\n indices: uncachedIndices.slice(batchStart, batchStart + MAX_BATCH_SIZE),\n });\n }\n\n // Process chunks with bounded concurrency (competitors do sequential)\n for (let ci = 0; ci < chunks.length; ci += MAX_CONCURRENCY) {\n const concurrentChunks = chunks.slice(ci, ci + MAX_CONCURRENCY);\n const batchStartOffset = ci * MAX_BATCH_SIZE;\n\n await Promise.all(concurrentChunks.map(async (chunk, chunkIdx) => {\n const body: Record<string, unknown> = {\n model: this.config.model,\n input: chunk.texts,\n };\n if (this.config.requestedDimensions) {\n body.dimensions = this.config.requestedDimensions;\n }\n\n const response = await fetchWithRetry(\n `${this.config.baseUrl}/embeddings`,\n this.config.apiKey,\n body,\n );\n\n this.trackUsage(response);\n\n const globalChunkStart = batchStartOffset + chunkIdx * MAX_BATCH_SIZE;\n\n // API may return results in any order — use the index field\n for (const item of response.data) {\n const originalIdx = chunk.indices[item.index];\n results[originalIdx] = item.embedding;\n cacheSet(textHash(uncachedTexts[globalChunkStart + item.index]), item.embedding);\n }\n }));\n }\n\n scheduleDiskSave();\n return results;\n }\n\n /**\n * Get usage stats for logging/debugging.\n */\n getStats(): { totalTokens: number; totalApiCalls: number; cacheSize: number } {\n return {\n totalTokens: this.totalTokensUsed,\n totalApiCalls: this.totalApiCalls,\n cacheSize: cache.size,\n };\n }\n\n private trackUsage(response: EmbeddingAPIResponse): void {\n this.totalApiCalls++;\n if (response.usage) {\n this.totalTokensUsed += response.usage.total_tokens;\n }\n }\n}\n\n// ─── HTTP with Retry ─────────────────────────────────────────────────\n\n/**\n * Fetch with exponential backoff retry.\n * Handles 429 (rate limit) and 5xx (server errors) gracefully.\n */\nasync function fetchWithRetry(\n url: string,\n apiKey: string,\n body: Record<string, unknown>,\n attempt = 0,\n): Promise<EmbeddingAPIResponse> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err: unknown) {\n clearTimeout(timeout);\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Embedding API timeout after 10s: ${url}`);\n }\n throw err;\n }\n clearTimeout(timeout);\n\n if (response.ok) {\n return response.json() as Promise<EmbeddingAPIResponse>;\n }\n\n // Retry on rate limit (429) or server errors (5xx)\n if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n const retryAfter = response.headers.get('retry-after');\n const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay;\n console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES} in ${waitMs}ms`);\n await new Promise(resolve => setTimeout(resolve, waitMs));\n return fetchWithRetry(url, apiKey, body, attempt + 1);\n }\n\n const errorText = await response.text().catch(() => 'unknown error');\n throw new Error(`Embedding API error (${response.status}): ${errorText}`);\n}\n","/**\n * Embedding Provider — Abstraction Layer\n *\n * Extensible embedding interface. **Disabled by default** to minimize resource usage.\n *\n * Environment variable MEMORIX_EMBEDDING controls which provider to use:\n * - MEMORIX_EMBEDDING=off (default) → no embedding, BM25 fulltext search only (~50MB RAM)\n * - MEMORIX_EMBEDDING=fastembed → local ONNX inference (384-dim bge-small, ~300MB RAM)\n * - MEMORIX_EMBEDDING=transformers → pure JS WASM inference (384-dim MiniLM, ~500MB RAM)\n * - MEMORIX_EMBEDDING=api → remote API via OpenAI-compatible /v1/embeddings (zero local RAM)\n * - MEMORIX_EMBEDDING=auto → try fastembed → transformers → off (legacy behavior)\n *\n * API mode env vars (MEMORIX_EMBEDDING=api):\n * - MEMORIX_EMBEDDING_API_KEY → API key (fallback: MEMORIX_LLM_API_KEY → OPENAI_API_KEY)\n * - MEMORIX_EMBEDDING_BASE_URL → base URL (fallback: MEMORIX_LLM_BASE_URL)\n * - MEMORIX_EMBEDDING_MODEL → model (default: text-embedding-3-small)\n * - MEMORIX_EMBEDDING_DIMENSIONS → optional dimension override\n *\n * Resource impact of local embedding:\n * - First load: 90%+ CPU for 5-30 seconds (model initialization)\n * - Steady state: 300-500MB RAM (model in memory)\n * - Per-query: 10-50ms CPU (embedding generation)\n *\n * Most users don't need vector search — BM25 fulltext is sufficient for keyword matching.\n * Vector search is useful for semantic similarity (e.g., \"auth\" matches \"authentication\").\n *\n * Architecture inspired by Mem0's multi-provider embedding design.\n */\n\nexport interface EmbeddingProvider {\n /** Provider name for logging/cache keys */\n readonly name: string;\n /** Vector dimensions (e.g., 384 for bge-small) */\n readonly dimensions: number;\n /** Generate embedding for a single text */\n embed(text: string): Promise<number[]>;\n /** Generate embeddings for multiple texts (batch) */\n embedBatch(texts: string[]): Promise<number[][]>;\n}\n\n/** Singleton provider instance (null = not available) */\nlet provider: EmbeddingProvider | null = null;\nlet initPromise: Promise<EmbeddingProvider | null> | null = null;\n\n/**\n * Get configured embedding mode from environment.\n * Default is 'off' to minimize resource usage.\n */\nfunction getEmbeddingMode(): 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' {\n // Unified: env vars > config.json > 'off'\n try {\n const { getEmbeddingMode: cfgMode } = require('../config.js');\n return cfgMode();\n } catch {\n // Fallback if config module not available\n const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();\n if (env === 'fastembed' || env === 'transformers' || env === 'api' || env === 'auto') return env;\n return 'off';\n }\n}\n\n/**\n * Get the embedding provider. Returns null if disabled or unavailable.\n * Lazy-initialized on first call. Concurrent callers share the same Promise.\n *\n * Controlled by MEMORIX_EMBEDDING environment variable (default: off).\n */\nexport async function getEmbeddingProvider(): Promise<EmbeddingProvider | null> {\n if (initPromise) return initPromise;\n\n initPromise = (async () => {\n const mode = getEmbeddingMode();\n\n // Explicit OFF — skip all embedding initialization\n if (mode === 'off') {\n console.error('[memorix] Embedding disabled (MEMORIX_EMBEDDING=off) — using BM25 fulltext search');\n return null;\n }\n\n // Explicit fastembed\n if (mode === 'fastembed') {\n try {\n const { FastEmbedProvider } = await import('./fastembed-provider.js');\n provider = await FastEmbedProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch (e) {\n console.error(`[memorix] Failed to load fastembed: ${e instanceof Error ? e.message : e}`);\n console.error('[memorix] Install with: npm install fastembed');\n return null;\n }\n }\n\n // Explicit transformers\n if (mode === 'transformers') {\n try {\n const { TransformersProvider } = await import('./transformers-provider.js');\n provider = await TransformersProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch (e) {\n console.error(`[memorix] Failed to load transformers: ${e instanceof Error ? e.message : e}`);\n console.error('[memorix] Install with: npm install @huggingface/transformers');\n return null;\n }\n }\n\n // API mode: remote embedding via OpenAI-compatible endpoint\n if (mode === 'api') {\n try {\n const { APIEmbeddingProvider } = await import('./api-provider.js');\n provider = await APIEmbeddingProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch (e) {\n console.error(`[memorix] Failed to init API embedding: ${e instanceof Error ? e.message : e}`);\n return null;\n }\n }\n\n // Auto mode: try fastembed → transformers → off (legacy behavior)\n try {\n const { FastEmbedProvider } = await import('./fastembed-provider.js');\n provider = await FastEmbedProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch {\n // fastembed not installed — try next\n }\n\n try {\n const { TransformersProvider } = await import('./transformers-provider.js');\n provider = await TransformersProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch {\n // transformers not installed — degrade to fulltext\n }\n\n console.error('[memorix] No embedding provider available — using BM25 fulltext search');\n return null;\n })();\n\n return initPromise;\n}\n\n/**\n * Check if vector search is available.\n */\nexport async function isVectorSearchAvailable(): Promise<boolean> {\n const p = await getEmbeddingProvider();\n return p !== null;\n}\n\n/**\n * Reset provider (for testing).\n */\nexport function resetProvider(): void {\n provider = null;\n initPromise = null;\n}\n","/**\n * Project Affinity Scoring\n *\n * Prevents cross-project memory pollution by scoring search results\n * based on how well they match the current project context.\n *\n * Inspired by mcp-memory-service's memory-scorer.js:\n * - High affinity: content mentions project name → full score\n * - Medium affinity: related concepts but no direct mention → 0.7x\n * - Low affinity: no project reference → 0.3x (heavily penalized)\n *\n * This runs AFTER projectId filtering, as a second layer of defense\n * against memories that were stored under the correct projectId but\n * contain content about a different project (e.g., discussing Memorix\n * development while in a test project workspace).\n */\n\nexport interface AffinityContext {\n /** Current project name (e.g., \"for_memmcp_test\", \"memorix\") */\n projectName: string;\n /** Current project ID (e.g., \"local/for_memmcp_test\", \"AVIDS2/memorix\") */\n projectId: string;\n /** Optional: keywords that indicate project relevance */\n projectKeywords?: string[];\n}\n\nexport interface MemoryContent {\n title: string;\n narrative?: string;\n facts?: string[];\n concepts?: string[];\n entityName?: string;\n filesModified?: string[];\n}\n\nexport interface AffinityResult {\n /** Affinity score 0-1 (1 = high affinity, 0 = no affinity) */\n score: number;\n /** Affinity level for debugging */\n level: 'high' | 'medium' | 'low' | 'none';\n /** Reason for the score */\n reason: string;\n}\n\n/**\n * Calculate project affinity score for a memory.\n *\n * @param memory - The memory content to evaluate\n * @param context - Current project context\n * @returns AffinityResult with score, level, and reason\n */\nexport function calculateProjectAffinity(\n memory: MemoryContent,\n context: AffinityContext,\n): AffinityResult {\n const projectName = context.projectName.toLowerCase();\n const projectId = context.projectId.toLowerCase();\n \n // Extract base name from projectId (e.g., \"memorix\" from \"AVIDS2/memorix\")\n const projectBaseName = projectId.split('/').pop() ?? projectName;\n \n // Build searchable content string\n const contentParts = [\n memory.title,\n memory.narrative ?? '',\n memory.entityName ?? '',\n ...(memory.facts ?? []),\n ...(memory.concepts ?? []),\n ...(memory.filesModified ?? []),\n ];\n const content = contentParts.join(' ').toLowerCase();\n \n // Check for direct project name mention\n if (content.includes(projectName) || content.includes(projectBaseName)) {\n return { score: 1.0, level: 'high', reason: 'project_name_in_content' };\n }\n \n // Check for project keywords (if provided)\n if (context.projectKeywords && context.projectKeywords.length > 0) {\n const keywordsLower = context.projectKeywords.map(k => k.toLowerCase());\n const matchedKeywords = keywordsLower.filter(k => content.includes(k));\n if (matchedKeywords.length >= 2) {\n return { score: 0.9, level: 'high', reason: `keywords_matched: ${matchedKeywords.join(', ')}` };\n }\n if (matchedKeywords.length === 1) {\n return { score: 0.7, level: 'medium', reason: `keyword_matched: ${matchedKeywords[0]}` };\n }\n }\n \n // Check for file paths that suggest project relevance\n const files = memory.filesModified ?? [];\n if (files.some(f => f.toLowerCase().includes(projectName) || f.toLowerCase().includes(projectBaseName))) {\n return { score: 0.85, level: 'high', reason: 'project_in_file_path' };\n }\n \n // Check entity name\n if (memory.entityName) {\n const entityLower = memory.entityName.toLowerCase();\n if (entityLower.includes(projectName) || entityLower.includes(projectBaseName)) {\n return { score: 0.8, level: 'high', reason: 'project_in_entity' };\n }\n }\n \n // Check concepts for project-related terms\n const concepts = memory.concepts ?? [];\n if (concepts.some(c => c.toLowerCase().includes(projectName) || c.toLowerCase().includes(projectBaseName))) {\n return { score: 0.75, level: 'medium', reason: 'project_in_concepts' };\n }\n \n // No project reference found — this memory might be about a different project\n // Apply penalty but don't completely filter (might still be relevant)\n return { score: 0.3, level: 'low', reason: 'no_project_reference' };\n}\n\n/**\n * Apply project affinity scoring to search results.\n *\n * @param results - Search results with scores\n * @param memories - Full memory content for each result (keyed by ID)\n * @param context - Current project context\n * @param options - Scoring options\n * @returns Results with adjusted scores, sorted by affinity-weighted score\n */\nexport function applyProjectAffinity<T extends { id: number; score: number }>(\n results: T[],\n memories: Map<number, MemoryContent>,\n context: AffinityContext,\n options: {\n /** Minimum affinity score to include (default: 0, include all) */\n minAffinity?: number;\n /** Whether to filter out low-affinity results entirely (default: false) */\n filterLowAffinity?: boolean;\n } = {},\n): T[] {\n const { minAffinity = 0, filterLowAffinity = false } = options;\n \n // Calculate affinity for each result\n const withAffinity = results.map(result => {\n const memory = memories.get(result.id);\n if (!memory) {\n // No memory content available — assume medium affinity\n return { ...result, affinity: 0.5, affinityLevel: 'medium' as const };\n }\n \n const { score: affinityScore, level } = calculateProjectAffinity(memory, context);\n return {\n ...result,\n score: result.score * affinityScore, // Apply affinity as multiplier\n affinity: affinityScore,\n affinityLevel: level,\n };\n });\n \n // Filter by minimum affinity if requested\n let filtered = withAffinity;\n if (filterLowAffinity) {\n filtered = withAffinity.filter(r => r.affinity >= 0.5);\n } else if (minAffinity > 0) {\n filtered = withAffinity.filter(r => r.affinity >= minAffinity);\n }\n \n // Re-sort by affinity-weighted score\n filtered.sort((a, b) => b.score - a.score);\n \n // Return without the extra affinity fields (keep original shape)\n return filtered.map(({ affinity: _, affinityLevel: __, ...rest }) => rest as T);\n}\n\n/**\n * Extract project keywords from project name and common patterns.\n * Used to improve affinity detection for projects with distinctive names.\n */\nexport function extractProjectKeywords(projectName: string, projectId: string): string[] {\n const keywords: string[] = [projectName];\n \n // Add base name from projectId\n const baseName = projectId.split('/').pop();\n if (baseName && baseName !== projectName) {\n keywords.push(baseName);\n }\n \n // Add common variations\n const variations = [\n projectName.replace(/-/g, '_'),\n projectName.replace(/_/g, '-'),\n projectName.replace(/[_-]/g, ''),\n ];\n for (const v of variations) {\n if (v !== projectName && !keywords.includes(v)) {\n keywords.push(v);\n }\n }\n \n return keywords.filter(k => k.length > 2);\n}\n","/**\n * Intent-Aware Recall — Query Intent Detection\n *\n * Detects the underlying intent of a search query (why/when/how/what)\n * and returns type-specific boosting factors to improve recall precision.\n *\n * Inspired by MemCP's intent routing architecture.\n * Uses fast keyword/pattern matching (no LLM needed).\n */\n\nimport type { ObservationType } from '../types.js';\n\n// ─── Types ───\n\nexport type QueryIntent = 'why' | 'when' | 'how' | 'what_changed' | 'problem' | 'general';\n\nexport interface IntentResult {\n /** Detected intent category */\n intent: QueryIntent;\n /** Confidence score 0-1 */\n confidence: number;\n /** Observation type → boost multiplier (applied to search scores) */\n typeBoosts: Partial<Record<ObservationType, number>>;\n /** Field weight overrides for Orama search (optional) */\n fieldBoosts?: Record<string, number>;\n /** Whether to prefer chronological ordering over relevance */\n preferChronological: boolean;\n}\n\n// ─── Intent Patterns ───\n\ninterface IntentPattern {\n intent: QueryIntent;\n patterns: RegExp[];\n /** Higher weight = stronger match when multiple intents match */\n weight: number;\n}\n\nconst INTENT_PATTERNS: IntentPattern[] = [\n {\n intent: 'why',\n patterns: [\n /\\bwhy\\b/i,\n /\\breason(?:s|ing)?\\b/i,\n /\\brationale\\b/i,\n /\\bmotivat(?:ion|ed)\\b/i,\n /\\bjustif(?:y|ication)\\b/i,\n /\\bchose|chosen|picked\\b/i,\n /\\bdecid(?:e[ds]?|ing)\\b/i,\n /\\btrade-?off\\b/i,\n /为什么/,\n /原因/,\n /理由/,\n /为何/,\n ],\n weight: 1.0,\n },\n {\n intent: 'when',\n patterns: [\n /\\bwhen\\b/i,\n /\\btimeline\\b/i,\n /\\bhistory\\b/i,\n /\\blast\\s+(week|month|time|session)\\b/i,\n /\\brecent(?:ly)?\\b/i,\n /\\byesterday\\b/i,\n /\\btoday\\b/i,\n /\\bchronolog/i,\n /什么时候/,\n /何时/,\n /最近/,\n /上次/,\n ],\n weight: 0.9,\n },\n {\n intent: 'how',\n patterns: [\n /\\bhow\\s+(does|do|to|is|can|did|should|would)\\b/i,\n /\\barchitecture\\b/i,\n /\\bmechanism\\b/i,\n /\\bimplement(?:ation|ed|ing)?\\b/i,\n /\\bwork(?:s|ing|ed)?\\b/i,\n /\\bexplain\\b/i,\n /\\bunderstand\\b/i,\n /怎么/,\n /如何/,\n /机制/,\n /原理/,\n /架构/,\n ],\n weight: 0.85,\n },\n {\n intent: 'what_changed',\n patterns: [\n /\\bwhat\\s+changed\\b/i,\n /\\bwhat\\s+was\\s+(modified|updated|changed)\\b/i,\n /\\bdiff(?:erence)?\\b/i,\n /\\bchangelog\\b/i,\n /\\bmodifi(?:ed|cation)\\b/i,\n /\\bupdat(?:e[ds]?|ing)\\b/i,\n /\\brefactor(?:ed|ing)?\\b/i,\n /改了/,\n /修改/,\n /变更/,\n /变化/,\n ],\n weight: 0.8,\n },\n {\n intent: 'problem',\n patterns: [\n /\\bbug(?:s|gy)?\\b/i,\n /\\berror(?:s)?\\b/i,\n /\\bfix(?:e[ds]|ing)?\\b/i,\n /\\bissue(?:s)?\\b/i,\n /\\bproblem(?:s)?\\b/i,\n /\\bcrash(?:e[ds]|ing)?\\b/i,\n /\\bfail(?:e[ds]|ure|ing)?\\b/i,\n /\\bbroken\\b/i,\n /\\bgotcha\\b/i,\n /\\bpitfall\\b/i,\n /\\bworkaround\\b/i,\n /\\btroubleshoot/i,\n /\\bdebug(?:ging)?\\b/i,\n /报错/,\n /问题/,\n /修复/,\n /故障/,\n /异常/,\n ],\n weight: 0.9,\n },\n];\n\n// ─── Type Boost Maps ───\n\nconst INTENT_TYPE_BOOSTS: Record<QueryIntent, Partial<Record<ObservationType, number>>> = {\n why: {\n 'decision': 3.0,\n 'why-it-exists': 3.0,\n 'trade-off': 2.5,\n 'how-it-works': 1.2,\n },\n when: {\n // Temporal queries don't strongly prefer any type — they prefer recency\n 'what-changed': 1.5,\n 'session-request': 1.3,\n },\n how: {\n 'how-it-works': 3.0,\n 'discovery': 2.0,\n 'decision': 1.3,\n },\n what_changed: {\n 'what-changed': 3.0,\n 'discovery': 1.5,\n 'session-request': 1.2,\n },\n problem: {\n 'problem-solution': 3.0,\n 'gotcha': 2.5,\n 'discovery': 1.3,\n },\n general: {\n // No special boosting\n },\n};\n\nconst INTENT_FIELD_BOOSTS: Partial<Record<QueryIntent, Record<string, number>>> = {\n why: {\n title: 2,\n entityName: 1.5,\n narrative: 2.5, // WHY queries need narrative context\n facts: 1.5,\n concepts: 1,\n filesModified: 0.3,\n },\n problem: {\n title: 3,\n entityName: 2,\n narrative: 2,\n facts: 2, // Bug details often in facts\n concepts: 1,\n filesModified: 1.5, // File paths help find the right bug fix\n },\n};\n\n// ─── Detection ───\n\n/**\n * Detect the intent of a search query.\n *\n * Returns the best matching intent with confidence score and\n * type-specific boosting factors to apply during search.\n */\nexport function detectQueryIntent(query: string): IntentResult {\n if (!query || query.length < 2) {\n return {\n intent: 'general',\n confidence: 0,\n typeBoosts: {},\n preferChronological: false,\n };\n }\n\n let bestIntent: QueryIntent = 'general';\n let bestScore = 0;\n let totalMatches = 0;\n\n for (const { intent, patterns, weight } of INTENT_PATTERNS) {\n let matchCount = 0;\n for (const pattern of patterns) {\n if (pattern.test(query)) matchCount++;\n }\n if (matchCount > 0) {\n const score = matchCount * weight;\n totalMatches += matchCount;\n if (score > bestScore) {\n bestScore = score;\n bestIntent = intent;\n }\n }\n }\n\n // Confidence: how strongly did we match vs. random noise\n const confidence = totalMatches === 0\n ? 0\n : Math.min(1, bestScore / 2); // 2+ pattern matches → high confidence\n\n return {\n intent: bestIntent,\n confidence,\n typeBoosts: INTENT_TYPE_BOOSTS[bestIntent],\n fieldBoosts: INTENT_FIELD_BOOSTS[bestIntent],\n preferChronological: bestIntent === 'when',\n };\n}\n\n/**\n * Apply intent-based type boosting to a search result's score.\n *\n * @param score Original search score\n * @param type Observation type of the result\n * @param intentResult Detected intent from detectQueryIntent()\n * @returns Boosted score\n */\nexport function applyIntentBoost(\n score: number,\n type: string,\n intentResult: IntentResult,\n): number {\n if (intentResult.confidence < 0.3) return score; // Low confidence → no boost\n const boost = intentResult.typeBoosts[type as ObservationType] ?? 1.0;\n // Scale boost by confidence: full boost at confidence=1, partial at lower\n const effectiveBoost = 1 + (boost - 1) * intentResult.confidence;\n return score * effectiveBoost;\n}\n","/**\n * Project Alias Registry\n *\n * Solves the \"project identity split\" problem: the same project gets different\n * projectIds depending on which IDE detects it (git remote vs local path vs placeholder).\n *\n * Maintains a registry file (~/.memorix/data/.project-aliases.json) that groups\n * all known IDs for the same physical project under one canonical ID.\n *\n * Canonical ID priority: git remote > local > placeholder\n *\n * Matching heuristics (any match → same project):\n * 1. Same normalized rootPath\n * 2. Same git remote URL\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { ProjectInfo } from '../types.js';\n\nconst DEFAULT_DATA_DIR = process.env.MEMORIX_DATA_DIR || path.join(os.homedir(), '.memorix', 'data');\nconst ALIAS_FILE = '.project-aliases.json';\n\n/** A group of project IDs that all refer to the same physical project */\nexport interface AliasGroup {\n /** The best-known ID for this project (git remote > local > placeholder) */\n canonical: string;\n /** All known IDs including canonical */\n aliases: string[];\n /** All known root paths (normalized) for this project */\n rootPaths: string[];\n /** Git remote URL if known */\n gitRemote?: string;\n}\n\ninterface AliasRegistry {\n version: 1;\n groups: AliasGroup[];\n}\n\n/** In-memory cache of the registry */\nlet registryCache: AliasRegistry | null = null;\nlet registryDir: string | null = null;\n\n/**\n * Normalize a root path for comparison.\n * - Forward slashes\n * - Lowercase on Windows\n * - No trailing slash\n */\nfunction normalizePath(p: string): string {\n let normalized = p.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n if (process.platform === 'win32') {\n normalized = normalized.toLowerCase();\n }\n return normalized;\n}\n\n/**\n * Determine the priority of a project ID prefix.\n * Higher = better canonical candidate.\n */\nfunction idPriority(id: string): number {\n if (id.startsWith('placeholder/')) return 0;\n if (id.startsWith('local/')) return 1;\n // Git remote-based IDs (e.g., \"user/repo\") have no prefix → highest priority\n return 2;\n}\n\n/**\n * Get the alias registry file path.\n */\nfunction getRegistryPath(baseDir?: string): string {\n return path.join(baseDir ?? registryDir ?? DEFAULT_DATA_DIR, ALIAS_FILE);\n}\n\n/**\n * Load the alias registry from disk.\n */\nasync function loadRegistry(baseDir?: string): Promise<AliasRegistry> {\n if (registryCache) return registryCache;\n try {\n const data = await fs.readFile(getRegistryPath(baseDir), 'utf-8');\n const parsed = JSON.parse(data);\n if (parsed.version === 1 && Array.isArray(parsed.groups)) {\n registryCache = parsed;\n return registryCache!;\n }\n } catch { /* file doesn't exist yet */ }\n registryCache = { version: 1, groups: [] };\n return registryCache;\n}\n\n/**\n * Save the alias registry to disk.\n */\nasync function saveRegistry(baseDir?: string): Promise<void> {\n if (!registryCache) return;\n const filePath = getRegistryPath(baseDir);\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, JSON.stringify(registryCache, null, 2), 'utf-8');\n}\n\n/**\n * Find an existing alias group that matches the given project info.\n *\n * Match criteria (any one is sufficient):\n * 1. Group already contains this exact ID\n * 2. Group has a matching normalized rootPath\n * 3. Group has a matching gitRemote\n */\nfunction findMatchingGroup(\n registry: AliasRegistry,\n projectInfo: ProjectInfo,\n): AliasGroup | null {\n const normalizedRoot = normalizePath(projectInfo.rootPath);\n\n for (const group of registry.groups) {\n // Match by ID\n if (group.aliases.includes(projectInfo.id)) return group;\n\n // Match by rootPath\n if (group.rootPaths.some((rp) => rp === normalizedRoot)) return group;\n\n // Match by git remote\n if (projectInfo.gitRemote && group.gitRemote && group.gitRemote === projectInfo.gitRemote) {\n return group;\n }\n }\n\n return null;\n}\n\n/**\n * Select the best canonical ID from a list of aliases.\n * Priority: git remote-based > local > placeholder\n */\nfunction selectCanonical(aliases: string[]): string {\n return [...aliases].sort((a, b) => idPriority(b) - idPriority(a))[0];\n}\n\n/**\n * Register a detected project in the alias registry.\n *\n * If the project matches an existing group, merges the new ID/rootPath into it.\n * If not, creates a new group.\n *\n * Returns the **canonical** project ID that should be used for storage and search.\n *\n * @param projectInfo - The detected project info from detectProject()\n * @param baseDir - Override data directory (for testing)\n * @returns The canonical project ID\n */\nexport async function registerAlias(projectInfo: ProjectInfo, baseDir?: string): Promise<string> {\n const registry = await loadRegistry(baseDir);\n const normalizedRoot = normalizePath(projectInfo.rootPath);\n\n const existingGroup = findMatchingGroup(registry, projectInfo);\n\n if (existingGroup) {\n // Merge into existing group\n let changed = false;\n\n if (!existingGroup.aliases.includes(projectInfo.id)) {\n existingGroup.aliases.push(projectInfo.id);\n changed = true;\n }\n\n if (!existingGroup.rootPaths.includes(normalizedRoot)) {\n existingGroup.rootPaths.push(normalizedRoot);\n changed = true;\n }\n\n if (projectInfo.gitRemote && !existingGroup.gitRemote) {\n existingGroup.gitRemote = projectInfo.gitRemote;\n changed = true;\n }\n\n // Re-evaluate canonical (maybe we just learned a git remote ID)\n const newCanonical = selectCanonical(existingGroup.aliases);\n if (newCanonical !== existingGroup.canonical) {\n existingGroup.canonical = newCanonical;\n changed = true;\n }\n\n if (changed) {\n await saveRegistry(baseDir);\n }\n\n return existingGroup.canonical;\n }\n\n // Create new group\n const newGroup: AliasGroup = {\n canonical: projectInfo.id,\n aliases: [projectInfo.id],\n rootPaths: [normalizedRoot],\n ...(projectInfo.gitRemote ? { gitRemote: projectInfo.gitRemote } : {}),\n };\n registry.groups.push(newGroup);\n await saveRegistry(baseDir);\n\n return newGroup.canonical;\n}\n\n/**\n * Resolve all known aliases for a project ID.\n *\n * Used in search to expand the projectId filter so that observations stored\n * under any alias are found regardless of which IDE stored them.\n *\n * @returns Array of all known IDs for the same project, or [projectId] if no aliases found.\n */\nexport async function resolveAliases(projectId: string, baseDir?: string): Promise<string[]> {\n const registry = await loadRegistry(baseDir);\n\n for (const group of registry.groups) {\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\n return [...group.aliases];\n }\n }\n\n return [projectId];\n}\n\n/**\n * Get the canonical ID for a project ID.\n *\n * @returns The canonical ID, or the input ID if no alias group found.\n */\nexport async function getCanonicalId(projectId: string, baseDir?: string): Promise<string> {\n const registry = await loadRegistry(baseDir);\n\n for (const group of registry.groups) {\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\n return group.canonical;\n }\n }\n\n return projectId;\n}\n\n/**\n * Get all alias groups (for dashboard/debug).\n */\nexport async function getAllAliasGroups(baseDir?: string): Promise<AliasGroup[]> {\n const registry = await loadRegistry(baseDir);\n return registry.groups;\n}\n\n/**\n * Auto-merge obvious alias groups by scanning existing observation projectIds.\n *\n * Detects project IDs that share the same base name but have different prefixes:\n * - placeholder/foo + local/foo → merge under the higher-priority one\n * - AVIDS2/test-repo + local/test-repo → merge under AVIDS2/test-repo\n *\n * Called once during server startup after observations are loaded.\n *\n * @param observedIds - All unique projectIds found in observations data\n * @returns Number of new merges performed\n */\nexport async function autoMergeByBaseName(\n observedIds: string[],\n baseDir?: string,\n): Promise<number> {\n if (observedIds.length <= 1) return 0;\n\n const registry = await loadRegistry(baseDir);\n\n // Group observed IDs by their base name (the part after the last /)\n const byBaseName = new Map<string, string[]>();\n for (const id of observedIds) {\n const baseName = id.split('/').pop() ?? id;\n if (!byBaseName.has(baseName)) byBaseName.set(baseName, []);\n byBaseName.get(baseName)!.push(id);\n }\n\n let mergeCount = 0;\n\n for (const [_baseName, ids] of byBaseName) {\n if (ids.length <= 1) continue;\n\n // Check if these IDs are already in the same alias group\n const existingGroups = new Set<number>();\n const ungroupedIds: string[] = [];\n\n for (const id of ids) {\n const groupIdx = registry.groups.findIndex(\n g => g.aliases.includes(id) || g.canonical === id,\n );\n if (groupIdx >= 0) {\n existingGroups.add(groupIdx);\n } else {\n ungroupedIds.push(id);\n }\n }\n\n // If all IDs are already in the same group, skip\n if (existingGroups.size <= 1 && ungroupedIds.length === 0) continue;\n\n // Merge: pick the best canonical from all IDs\n const allIdsInGroup = [...ids];\n const canonical = selectCanonical(allIdsInGroup);\n\n if (existingGroups.size > 0) {\n // Merge into the first existing group\n const primaryIdx = [...existingGroups][0];\n const primaryGroup = registry.groups[primaryIdx];\n\n // Add all IDs to primary group\n for (const id of allIdsInGroup) {\n if (!primaryGroup.aliases.includes(id)) {\n primaryGroup.aliases.push(id);\n }\n }\n\n // Absorb other existing groups into primary\n const otherIdxs = [...existingGroups].slice(1).sort((a, b) => b - a);\n for (const idx of otherIdxs) {\n const other = registry.groups[idx];\n for (const alias of other.aliases) {\n if (!primaryGroup.aliases.includes(alias)) {\n primaryGroup.aliases.push(alias);\n }\n }\n for (const rp of other.rootPaths) {\n if (!primaryGroup.rootPaths.includes(rp)) {\n primaryGroup.rootPaths.push(rp);\n }\n }\n if (other.gitRemote && !primaryGroup.gitRemote) {\n primaryGroup.gitRemote = other.gitRemote;\n }\n registry.groups.splice(idx, 1);\n }\n\n // Re-evaluate canonical\n primaryGroup.canonical = selectCanonical(primaryGroup.aliases);\n mergeCount++;\n } else {\n // All ungrouped — create new group\n registry.groups.push({\n canonical,\n aliases: allIdsInGroup,\n rootPaths: [],\n });\n mergeCount++;\n }\n }\n\n if (mergeCount > 0) {\n await saveRegistry(baseDir);\n }\n\n return mergeCount;\n}\n\n/**\n * Initialize the alias registry with a data directory.\n * Should be called once during server startup.\n */\nexport function initAliasRegistry(dataDir: string): void {\n registryDir = dataDir;\n registryCache = null; // Force reload from new location\n}\n\n/**\n * Reset the in-memory cache (for testing).\n */\nexport function resetAliasCache(): void {\n registryCache = null;\n}\n","/**\n * LLM Provider\n *\n * Abstraction layer for LLM-enhanced memory management.\n * Supports OpenAI-compatible APIs (OpenAI, Anthropic via proxy, local models).\n *\n * This is the optional \"premium\" path — Memorix works without it,\n * but with an LLM configured, memory quality approaches Mem0/Cipher level.\n */\n\nexport interface LLMConfig {\n provider: 'openai' | 'anthropic' | 'openrouter' | 'custom';\n apiKey: string;\n model?: string;\n baseUrl?: string;\n}\n\nexport interface LLMResponse {\n content: string;\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/** Provider defaults per provider type */\nconst PROVIDER_DEFAULTS: Record<string, { baseUrl: string; model: string }> = {\n openai: { baseUrl: 'https://api.openai.com/v1', model: 'gpt-4.1-nano' },\n anthropic: { baseUrl: 'https://api.anthropic.com/v1', model: 'claude-3-5-haiku-latest' },\n openrouter: { baseUrl: 'https://openrouter.ai/api/v1', model: 'openai/gpt-4.1-nano' },\n custom: { baseUrl: 'http://localhost:11434/v1', model: 'llama3' },\n};\n\nlet currentConfig: LLMConfig | null = null;\n\n/**\n * Initialize the LLM provider from environment variables.\n * Returns null if no API key is configured — Memorix gracefully degrades.\n */\nexport function initLLM(): LLMConfig | null {\n // Unified config: env vars > config.json > defaults\n const { getLLMApiKey, getLLMProvider, getLLMModel, getLLMBaseUrl } = require('../config.js');\n\n const apiKey = getLLMApiKey();\n if (!apiKey) {\n currentConfig = null;\n return null;\n }\n\n const provider = getLLMProvider() as LLMConfig['provider'];\n const defaults = PROVIDER_DEFAULTS[provider] ?? PROVIDER_DEFAULTS.openai;\n\n currentConfig = {\n provider,\n apiKey,\n model: getLLMModel(defaults.model),\n baseUrl: getLLMBaseUrl(defaults.baseUrl),\n };\n\n return currentConfig;\n}\n\n/**\n * Check if LLM is available.\n */\nexport function isLLMEnabled(): boolean {\n return currentConfig !== null;\n}\n\n/**\n * Get current LLM config (for display/debug).\n */\nexport function getLLMConfig(): LLMConfig | null {\n return currentConfig;\n}\n\n/**\n * Call the LLM with a prompt.\n * Uses OpenAI-compatible chat completions API (works with OpenRouter, Ollama, etc.)\n *\n * For Anthropic, we use their Messages API directly.\n */\nexport async function callLLM(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n if (!currentConfig) {\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\n }\n\n if (currentConfig.provider === 'anthropic') {\n return callAnthropic(systemPrompt, userMessage);\n }\n\n return callOpenAICompatible(systemPrompt, userMessage);\n}\n\n/**\n * OpenAI-compatible API call (works with OpenAI, OpenRouter, Ollama, etc.)\n */\nasync function callOpenAICompatible(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n const config = currentConfig!;\n // Auto-fix: append /v1 if baseUrl doesn't end with it (common user mistake)\n let base = config.baseUrl!.replace(/\\/+$/, '');\n if (!base.endsWith('/v1')) base += '/v1';\n const url = `${base}/chat/completions`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage },\n ],\n temperature: 0.1,\n max_tokens: 1024,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text().catch(() => 'unknown error');\n throw new Error(`LLM API error (${response.status}): ${error}`);\n }\n\n const data = await response.json() as {\n choices: Array<{ message: { content: string } }>;\n usage?: { prompt_tokens: number; completion_tokens: number };\n };\n\n return {\n content: data.choices[0]?.message?.content ?? '',\n usage: data.usage ? {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n } : undefined,\n };\n}\n\n/**\n * Anthropic Messages API call.\n */\nasync function callAnthropic(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n const config = currentConfig!;\n const url = `${config.baseUrl}/messages`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: config.model,\n system: systemPrompt,\n messages: [\n { role: 'user', content: userMessage },\n ],\n temperature: 0.1,\n max_tokens: 1024,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text().catch(() => 'unknown error');\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\n }\n\n const data = await response.json() as {\n content: Array<{ text: string }>;\n usage?: { input_tokens: number; output_tokens: number };\n };\n\n return {\n content: data.content[0]?.text ?? '',\n usage: data.usage ? {\n promptTokens: data.usage.input_tokens,\n completionTokens: data.usage.output_tokens,\n } : undefined,\n };\n}\n","/**\n * LLM Quality Enhancements\n *\n * Premium memory quality features powered by LLM:\n * 1. Narrative Compression — compress verbose narratives into concise core knowledge\n * 2. Search Reranking — rerank search results by relevance to current task context\n *\n * Both features gracefully degrade: when LLM is not configured, they return\n * the original data unchanged.\n *\n * Performance targets:\n * - Compression: ~60% token reduction per stored memory\n * - Reranking: ~40% improvement in Top-5 precision\n */\n\nimport { callLLM, isLLMEnabled } from './provider.js';\n\n// ── Narrative Compression ────────────────────────────────────────\n\nconst COMPRESS_PROMPT = `You are a memory compression engine for a coding assistant.\n\nCompress the given narrative into the shortest possible form that preserves ALL technical facts.\n\nRules:\n- Aggressively remove: filler words, background context, debugging journey, repeated info\n- Compress to MINIMUM viable length — aim for 50% or less of original\n- Keep ONLY: specific values, file paths, error messages, version numbers, config keys, causal relationships\n- Merge related points into single dense sentences\n- If facts are provided separately, do NOT repeat them in the compressed narrative\n- Output the compressed text ONLY, no explanation or wrapper\n\nExamples:\nInput: \"我在调试过程中发现JWT token的refresh机制存在问题,具体来说是因为服务端没有实现自动续签,导致用户在24小时后会遇到静默的认证失败,之前我一直以为是网络问题但后来排查发现是token过期了\"\nOutput: \"JWT refresh无自动续签→24h后静默认证失败(非网络问题)\"\n\nInput: \"Final deployment model for shadcn-blog is stable: GitHub Actions build locally, SCP artifacts to VPS, systemd manages the process. Docker was considered but rejected due to complexity overhead for a simple blog. The whole pipeline takes about 2 minutes from push to live.\"\nOutput: \"shadcn-blog部署: GH Actions构建→SCP到VPS→systemd管理, 弃Docker(复杂度过高), push到上线~2min\"`;\n\n/**\n * Compress a narrative to its essential core using LLM.\n *\n * Returns the original narrative if:\n * - LLM is not enabled\n * - Narrative is already short (≤80 chars)\n * - Narrative is already concise (commands, file paths, git operations)\n * - LLM call fails\n */\nexport async function compressNarrative(\n narrative: string,\n facts?: string[],\n type?: string,\n): Promise<{ compressed: string; saved: number; usedLLM: boolean }> {\n const originalTokens = estimateTokens(narrative);\n\n // Skip compression for short narratives\n if (!isLLMEnabled() || narrative.length <= 80) {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n\n // Skip compression for already-concise content that LLM can't meaningfully compress\n if (shouldSkipCompression(narrative, type)) {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n\n try {\n const factsContext = facts && facts.length > 0\n ? `\\n\\nSeparate facts (already stored, don't repeat): ${facts.join('; ')}`\n : '';\n\n const response = await callLLM(COMPRESS_PROMPT, narrative + factsContext);\n const compressed = response.content.trim();\n\n // Sanity check: compressed should be shorter and non-empty\n if (!compressed || compressed.length >= narrative.length) {\n return { compressed: narrative, saved: 0, usedLLM: true };\n }\n\n const compressedTokens = estimateTokens(compressed);\n return {\n compressed,\n saved: originalTokens - compressedTokens,\n usedLLM: true,\n };\n } catch {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n}\n\n// ── Search Reranking ─────────────────────────────────────────────\n\n/** Minimal search result for reranking */\nexport interface RerankCandidate {\n id: number;\n title: string;\n type: string;\n score: number;\n narrative?: string;\n}\n\nconst RERANK_PROMPT = `You are a memory relevance ranker for a coding assistant.\n\nGiven a QUERY (what the user/agent is looking for) and a list of CANDIDATE memories,\nrerank them by relevance to the query.\n\nRules:\n- Consider semantic relevance, not just keyword overlap\n- Gotchas and decisions related to the query topic should rank higher\n- Recent problem-solutions for the same component should rank higher\n- Generic or loosely related memories should rank lower\n- Output ONLY a JSON array of IDs in order of relevance (most relevant first)\n- Include ALL candidate IDs, just reorder them\n\nExample output: [42, 15, 87, 3, 21]`;\n\n/**\n * Rerank search results using LLM contextual understanding.\n *\n * Takes Orama's initial ranking and improves it by considering\n * semantic relevance to the current query/task context.\n *\n * Returns original order if LLM is not enabled or call fails.\n */\nexport async function rerankResults(\n query: string,\n candidates: RerankCandidate[],\n): Promise<{ reranked: RerankCandidate[]; usedLLM: boolean }> {\n // Skip if too few results or LLM not available\n if (!isLLMEnabled() || candidates.length <= 2) {\n return { reranked: candidates, usedLLM: false };\n }\n\n // Only rerank top-N to save LLM tokens (reranking 20+ is wasteful)\n const MAX_RERANK = 10;\n const toRerank = candidates.slice(0, MAX_RERANK);\n const rest = candidates.slice(MAX_RERANK);\n\n try {\n const candidateList = toRerank.map(c =>\n `[ID: ${c.id}] (${c.type}) ${c.title}${c.narrative ? ` — ${c.narrative.substring(0, 100)}` : ''}`,\n ).join('\\n');\n\n const response = await callLLM(RERANK_PROMPT, `QUERY: ${query}\\n\\nCANDIDATES:\\n${candidateList}`);\n\n // Parse response — handle markdown code blocks\n let content = response.content.trim();\n if (content.startsWith('```')) {\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\n }\n\n const rankedIds = JSON.parse(content) as number[];\n\n // Validate: must be an array of numbers matching our candidates\n if (!Array.isArray(rankedIds) || rankedIds.length === 0) {\n return { reranked: candidates, usedLLM: true };\n }\n\n // Build reranked list preserving original scores for display\n const idMap = new Map(toRerank.map(c => [c.id, c]));\n const reranked: RerankCandidate[] = [];\n const seen = new Set<number>();\n\n // Add IDs in LLM-reranked order\n for (const id of rankedIds) {\n const candidate = idMap.get(id);\n if (candidate && !seen.has(id)) {\n reranked.push(candidate);\n seen.add(id);\n }\n }\n\n // Add any candidates the LLM missed (safety: never lose results)\n for (const c of toRerank) {\n if (!seen.has(c.id)) {\n reranked.push(c);\n }\n }\n\n // Append non-reranked tail\n reranked.push(...rest);\n\n return { reranked, usedLLM: true };\n } catch {\n return { reranked: candidates, usedLLM: false };\n }\n}\n\n// ── Smart Compression Filtering ──────────────────────────────────\n\n/** Patterns that indicate already-concise content not worth compressing */\nconst SKIP_PATTERNS = [\n /^(?:Command|Run|Execute):\\s/i, // Shell commands\n /^(?:File|Edit|Changed):\\s/i, // File change descriptions\n /^git\\s+(?:add|commit|push|pull|log)/i, // Git operations\n /^(?:npm|npx|pnpm|yarn|bun)\\s/i, // Package manager commands\n /^(?:Remove-Item|New-Item|Set-Content)/i, // PowerShell commands\n /^[A-Za-z]:\\\\[\\w\\\\]/, // Windows file paths\n /^\\/(?:usr|home|var|etc|opt)\\//, // Unix file paths\n];\n\n/** Low-value observation types that hooks auto-capture (usually already terse) */\nconst LOW_COMPRESSION_TYPES = new Set(['what-changed', 'discovery', 'session-request']);\n\n/**\n * Determine if a narrative should skip LLM compression.\n *\n * Skip when:\n * - Content starts with command/path patterns (already structured, not prose)\n * - Type is hooks-auto-captured AND narrative is relatively short\n * - Narrative is mostly code/paths (high ratio of special chars)\n */\nfunction shouldSkipCompression(narrative: string, type?: string): boolean {\n // Skip command/path-like content\n const firstLine = narrative.split('\\n')[0];\n if (SKIP_PATTERNS.some(p => p.test(firstLine))) return true;\n\n // Skip short auto-captured observations (hooks produce terse what-changed)\n if (type && LOW_COMPRESSION_TYPES.has(type) && narrative.length < 200) return true;\n\n // Skip if narrative is mostly code/structured data (high special char ratio)\n const specialChars = (narrative.match(/[{}()\\[\\]<>:;=|\\\\\\/\\-_\\.@#$%^&*+~`\"']/g) || []).length;\n if (specialChars / narrative.length > 0.35) return true;\n\n return false;\n}\n\n// ── Utility ──────────────────────────────────────────────────────\n\n/** Rough token estimate: ~4 chars per token for English, ~2 for CJK */\nfunction estimateTokens(text: string): number {\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length;\n const otherChars = text.length - cjkChars;\n return Math.ceil(cjkChars / 1.5 + otherChars / 4);\n}\n","/**\n * Orama Store\n *\n * Full-text + vector + hybrid search engine backed by Orama.\n * Source: @orama/orama (10.1K stars, <2KB, pure JS, zero deps)\n *\n * Schema designed to store Observations with all searchable fields.\n * Vector search (embeddings) will be added in P1 phase.\n */\n\nimport { create, insert, search, remove, update, count, type AnyOrama } from '@orama/orama';\nimport type { MemorixDocument, SearchOptions, IndexEntry } from '../types.js';\nimport { OBSERVATION_ICONS, type ObservationType } from '../types.js';\nimport { getEmbeddingProvider, type EmbeddingProvider } from '../embedding/provider.js';\nimport { calculateProjectAffinity, extractProjectKeywords, type AffinityContext, type MemoryContent } from './project-affinity.js';\nimport { detectQueryIntent, applyIntentBoost } from '../search/intent-detector.js';\n\nlet db: AnyOrama | null = null;\nlet embeddingEnabled = false;\n\n/**\n * Initialize or return the Orama database instance.\n * Schema conditionally includes vector field based on embedding provider.\n * Graceful degradation: no provider → fulltext only, provider → hybrid.\n */\nexport async function getDb(): Promise<AnyOrama> {\n if (db) return db;\n\n // Check if embedding provider is available\n const provider = await getEmbeddingProvider();\n embeddingEnabled = provider !== null;\n\n const baseSchema = {\n id: 'string' as const,\n observationId: 'number' as const,\n entityName: 'string' as const,\n type: 'string' as const,\n title: 'string' as const,\n narrative: 'string' as const,\n facts: 'string' as const,\n filesModified: 'string' as const,\n concepts: 'string' as const,\n tokens: 'number' as const,\n createdAt: 'string' as const,\n projectId: 'string' as const,\n accessCount: 'number' as const,\n lastAccessedAt: 'string' as const,\n status: 'string' as const,\n };\n\n // Dynamic vector dimensions based on provider (384 for local, 1024+ for API)\n const dims = provider?.dimensions ?? 384;\n const schema = embeddingEnabled\n ? { ...baseSchema, embedding: `vector[${dims}]` as const }\n : baseSchema;\n\n db = await create({ schema });\n\n return db;\n}\n\n/**\n * Reset the database instance (useful for testing).\n */\nexport async function resetDb(): Promise<void> {\n db = null;\n embeddingEnabled = false;\n}\n\n/**\n * Check if embedding/vector search is active.\n */\nexport function isEmbeddingEnabled(): boolean {\n return embeddingEnabled;\n}\n\n/**\n * Generate embedding for text content using the available provider.\n * Returns null if no provider is available.\n */\nexport async function generateEmbedding(text: string): Promise<number[] | null> {\n const provider = await getEmbeddingProvider();\n if (!provider) return null;\n return provider.embed(text);\n}\n\n/**\n * Batch-generate embeddings for multiple texts.\n * Much faster than individual calls — ONNX processes batches of 64 in parallel.\n * Returns null entries for texts that fail.\n */\nexport async function batchGenerateEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n const provider = await getEmbeddingProvider();\n if (!provider || texts.length === 0) return texts.map(() => null);\n try {\n const results = await provider.embedBatch(texts);\n return results;\n } catch {\n return texts.map(() => null);\n }\n}\n\n/**\n * Insert an observation document into the store.\n */\nexport async function insertObservation(doc: MemorixDocument): Promise<void> {\n const database = await getDb();\n await insert(database, doc);\n}\n\n/**\n * Remove an observation document by its Orama internal ID.\n */\nexport async function removeObservation(oramaId: string): Promise<void> {\n const database = await getDb();\n await remove(database, oramaId);\n}\n\n/**\n * Search observations using Orama full-text search.\n * Returns L1 IndexEntry array (compact, ~50-100 tokens per result).\n *\n * Progressive Disclosure Layer 1 — adopted from claude-mem.\n */\nexport async function searchObservations(options: SearchOptions): Promise<IndexEntry[]> {\n const database = await getDb();\n\n // Resolve project aliases — safety net for observations not yet migrated to canonical ID.\n // After migration, this is typically a single-element array matching options.projectId.\n let projectIds: string[] | null = null;\n if (options.projectId) {\n try {\n const { resolveAliases } = await import('../project/aliases.js');\n projectIds = await resolveAliases(options.projectId);\n } catch {\n projectIds = [options.projectId];\n }\n }\n\n const filters: Record<string, unknown> = {};\n if (projectIds && projectIds.length === 1) {\n filters['projectId'] = projectIds[0];\n }\n // If multiple aliases exist, we skip the Orama projectId filter and post-filter instead\n if (options.type) {\n filters['type'] = options.type;\n }\n\n // Determine search mode: hybrid (with vector) or fulltext (default)\n const hasQuery = options.query && options.query.trim().length > 0;\n\n // ── Intent-Aware Recall ──────────────────────────────────────\n // Detect query intent (why/when/how/what/problem) and adjust\n // field weights and type boosting accordingly.\n const intentResult = hasQuery ? detectQueryIntent(options.query!) : null;\n\n // When post-filtering by multiple project aliases, request extra results to compensate\n const requestLimit = (projectIds && projectIds.length > 1)\n ? (options.limit ?? 20) * 3\n : (options.limit ?? 20);\n\n // Default field boosts — overridden by intent-specific boosts when detected\n const defaultBoost: Record<string, number> = {\n title: 3,\n entityName: 2,\n concepts: 1.5,\n narrative: 1,\n facts: 1,\n filesModified: 0.5,\n };\n const fieldBoost = (intentResult?.confidence ?? 0) > 0.3 && intentResult?.fieldBoosts\n ? intentResult.fieldBoosts\n : defaultBoost;\n\n let searchParams: Record<string, unknown> = {\n term: options.query,\n limit: requestLimit,\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\n // Search specific fields (not tokens, accessCount, etc.)\n properties: ['title', 'entityName', 'narrative', 'facts', 'concepts', 'filesModified'],\n // Field boosting: intent-aware or default\n boost: fieldBoost,\n // Fuzzy tolerance: allow 1-char typos for short queries, 2 for longer\n ...(hasQuery ? { tolerance: options.query!.length > 6 ? 2 : 1 } : {}),\n };\n\n // If embedding provider is available and we have a query, use hybrid search\n let queryVector: number[] | null = null;\n if (embeddingEnabled && hasQuery) {\n try {\n const provider = await getEmbeddingProvider();\n if (provider) {\n queryVector = await provider.embed(options.query!);\n // Detect CJK-heavy queries: BM25 can't tokenize Chinese/Japanese/Korean well\n const cjkRatio = (options.query!.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length / options.query!.length;\n const isCJKHeavy = cjkRatio > 0.3;\n searchParams = {\n ...searchParams,\n mode: 'hybrid',\n vector: {\n value: queryVector,\n property: 'embedding',\n },\n similarity: isCJKHeavy ? 0.3 : 0.5,\n hybridWeights: isCJKHeavy\n ? { text: 0.2, vector: 0.8 } // CJK: trust vector over BM25\n : { text: 0.6, vector: 0.4 },\n };\n }\n } catch {\n // Fallback to fulltext if embedding fails\n }\n }\n\n let results = await search(database, searchParams);\n\n // Fallback: if hybrid returned nothing but we have a vector, retry with vector-only\n if (results.count === 0 && queryVector && embeddingEnabled) {\n try {\n const vectorOnlyParams: Record<string, unknown> = {\n term: '',\n limit: requestLimit,\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\n mode: 'vector',\n vector: {\n value: queryVector,\n property: 'embedding',\n },\n similarity: 0.25,\n };\n results = await search(database, vectorOnlyParams);\n } catch {\n // Keep original empty results\n }\n }\n\n // Status filter: default to 'active' only\n const statusFilter = options.status ?? 'active';\n\n // Build intermediate results with rawTime for temporal filtering\n let intermediate = results.hits\n // Post-filter by project aliases when multiple aliases exist (Orama doesn't support `in` for strings)\n .filter((hit) => {\n if (!projectIds || projectIds.length <= 1) return true;\n const doc = hit.document as unknown as MemorixDocument;\n return projectIds.includes(doc.projectId);\n })\n // Post-filter by status (active/resolved/archived)\n .filter((hit) => {\n if (statusFilter === 'all') return true;\n const doc = hit.document as unknown as MemorixDocument;\n return (doc.status || 'active') === statusFilter;\n })\n .map((hit) => {\n const doc = hit.document as unknown as MemorixDocument;\n const obsType = doc.type as ObservationType;\n // Time decay: newer memories get higher boost\n const ageMs = Date.now() - new Date(doc.createdAt).getTime();\n const DAY = 86_400_000;\n let recencyBoost: number;\n if (ageMs < 1 * DAY) recencyBoost = 1.0;\n else if (ageMs < 7 * DAY) recencyBoost = 0.85;\n else if (ageMs < 30 * DAY) recencyBoost = 0.6;\n else recencyBoost = 0.35;\n\n return {\n id: doc.observationId,\n time: formatTime(doc.createdAt),\n rawTime: doc.createdAt,\n type: obsType,\n icon: OBSERVATION_ICONS[obsType] ?? '❓',\n title: doc.title,\n tokens: doc.tokens,\n score: (hit.score ?? 1) * recencyBoost,\n };\n });\n\n // ── Intent-Aware Type Boosting ───────────────────────────────\n // Boost scores for observation types that match the query intent\n if (intentResult && intentResult.confidence > 0.3) {\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: applyIntentBoost(entry.score, entry.type, intentResult),\n }));\n }\n\n // Re-sort: chronological for WHEN queries, relevance for others\n if (intentResult?.preferChronological) {\n intermediate.sort((a, b) => new Date(b.rawTime).getTime() - new Date(a.rawTime).getTime());\n } else {\n intermediate.sort((a, b) => b.score - a.score);\n }\n\n // ─── Project Affinity Scoring (mcp-memory-service style) ───\n // Penalize memories that don't reference the current project to prevent\n // cross-project pollution (e.g., discussing Memorix in a test project workspace)\n if (options.projectId && intermediate.length > 0) {\n const projectName = options.projectId.split('/').pop() ?? options.projectId;\n const affinityContext: AffinityContext = {\n projectName,\n projectId: options.projectId,\n projectKeywords: extractProjectKeywords(projectName, options.projectId),\n };\n\n // Build a map of memory content for affinity calculation\n const memoryContentMap = new Map<number, MemoryContent>();\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n memoryContentMap.set(doc.observationId, {\n title: doc.title,\n narrative: doc.narrative,\n facts: doc.facts?.split?.('\\n') ?? (Array.isArray(doc.facts) ? doc.facts : []),\n concepts: doc.concepts?.split?.('\\n') ?? (Array.isArray(doc.concepts) ? doc.concepts : []),\n entityName: doc.entityName,\n filesModified: doc.filesModified?.split?.('\\n') ?? (Array.isArray(doc.filesModified) ? doc.filesModified : []),\n });\n }\n\n // Apply affinity scoring to each result\n intermediate = intermediate.map(entry => {\n const memory = memoryContentMap.get(entry.id);\n if (!memory) return entry;\n\n const { score: affinityScore } = calculateProjectAffinity(memory, affinityContext);\n return {\n ...entry,\n score: entry.score * affinityScore, // Apply affinity as multiplier\n };\n });\n\n // Re-sort after affinity adjustment\n intermediate.sort((a, b) => b.score - a.score);\n }\n\n // Temporal filtering: since/until date range\n if (options.since) {\n const sinceDate = new Date(options.since).getTime();\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() >= sinceDate);\n }\n if (options.until) {\n const untilDate = new Date(options.until).getTime();\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() <= untilDate);\n }\n\n // Apply original limit after post-filtering (we requested extra when multi-alias post-filter is active)\n if (projectIds && projectIds.length > 1) {\n intermediate = intermediate.slice(0, options.limit ?? 20);\n }\n\n // ── LLM Reranking (premium quality) ────────────────────────────\n // After Orama + recency + affinity scoring, use LLM to rerank by\n // semantic relevance to the actual query context.\n // ~40% improvement in Top-5 precision when enabled.\n if (hasQuery && intermediate.length > 2) {\n try {\n const { rerankResults } = await import('../llm/quality.js');\n // Build narrative snippets from original search hits for richer reranking\n const narrativeMap = new Map<number, string>();\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n narrativeMap.set(doc.observationId, doc.narrative);\n }\n const candidates = intermediate.map(e => ({\n id: e.id,\n title: e.title,\n type: e.type,\n score: e.score,\n narrative: narrativeMap.get(e.id),\n }));\n const { reranked, usedLLM } = await rerankResults(options.query!, candidates);\n if (usedLLM) {\n // Rebuild intermediate with reranked order, preserving all original fields\n const intermediateMap = new Map(intermediate.map(e => [e.id, e]));\n const rerankedIntermediate = reranked\n .map(r => intermediateMap.get(r.id))\n .filter((e): e is NonNullable<typeof e> => e != null);\n if (rerankedIntermediate.length > 0) {\n intermediate = rerankedIntermediate;\n }\n }\n } catch { /* reranking is best-effort */ }\n }\n\n // Build IndexEntry with optional match explanation\n let entries: IndexEntry[] = intermediate.map(({ rawTime: _, ...rest }) => rest);\n\n // Explainable recall: annotate entries with match reasons (O(1) lookup via Map)\n if (hasQuery && options.query) {\n const queryLower = options.query.toLowerCase();\n const queryTokens = queryLower.split(/\\s+/).filter(t => t.length > 1);\n const entryMap = new Map(entries.map(e => [e.id, e]));\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n const entry = entryMap.get(doc.observationId);\n if (!entry) continue;\n\n const reasons: string[] = [];\n const fields: [string, string][] = [\n ['title', doc.title], ['entity', doc.entityName], ['concept', doc.concepts],\n ['narrative', doc.narrative], ['fact', doc.facts], ['file', doc.filesModified],\n ];\n for (const [name, value] of fields) {\n const valueLower = value.toLowerCase();\n if (queryTokens.some(t => valueLower.includes(t))) reasons.push(name);\n }\n if (reasons.length === 0) reasons.push('fuzzy');\n (entry as unknown as Record<string, unknown>)['matchedFields'] = reasons;\n }\n }\n\n // Apply token budget if specified (inspired by MemCP)\n if (options.maxTokens && options.maxTokens > 0) {\n entries = applyTokenBudget(entries, options.maxTokens);\n }\n\n // Record access for returned results (fire-and-forget, non-blocking)\n const hitDocs = results.hits.map((h) => ({ id: h.id, doc: h.document as unknown as MemorixDocument }));\n recordAccessBatch(hitDocs).catch(() => {});\n\n return entries;\n}\n\n/**\n * Get full observation documents by their observation IDs.\n *\n * Progressive Disclosure Layer 3 — adopted from claude-mem.\n */\nexport async function getObservationsByIds(\n ids: number[],\n projectId?: string,\n): Promise<MemorixDocument[]> {\n const database = await getDb();\n\n // Search for each ID individually and collect results\n const results: MemorixDocument[] = [];\n\n for (const id of ids) {\n const searchResult = await search(database, {\n term: '',\n where: {\n observationId: { eq: id },\n ...(projectId ? { projectId } : {}),\n },\n limit: 1,\n });\n\n if (searchResult.hits.length > 0) {\n results.push(searchResult.hits[0].document as unknown as MemorixDocument);\n }\n }\n\n return results;\n}\n\n/**\n * Get observations around an anchor for timeline context.\n *\n * Progressive Disclosure Layer 2 — adopted from claude-mem.\n */\nexport async function getTimeline(\n anchorId: number,\n _projectId?: string,\n depthBefore = 3,\n depthAfter = 3,\n): Promise<{ before: IndexEntry[]; anchor: IndexEntry | null; after: IndexEntry[] }> {\n // Use in-memory observations for reliable lookup\n // (Orama search with empty term is unreliable — same fix as compactDetail)\n const { getAllObservations } = await import('../memory/observations.js');\n const allObs = getAllObservations();\n\n // Sort by creation time\n const sorted = allObs.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n\n const anchorIndex = sorted.findIndex((o) => o.id === anchorId);\n if (anchorIndex === -1) {\n return { before: [], anchor: null, after: [] };\n }\n\n const toIndexEntry = (obs: { id: number; type: string; title: string; tokens: number; createdAt: string }): IndexEntry => {\n const obsType = obs.type as ObservationType;\n return {\n id: obs.id,\n time: formatTime(obs.createdAt),\n type: obsType,\n icon: OBSERVATION_ICONS[obsType] ?? '❓',\n title: obs.title,\n tokens: obs.tokens,\n };\n };\n\n const before = sorted\n .slice(Math.max(0, anchorIndex - depthBefore), anchorIndex)\n .map(toIndexEntry);\n\n const after = sorted\n .slice(anchorIndex + 1, anchorIndex + 1 + depthAfter)\n .map(toIndexEntry);\n\n return {\n before,\n anchor: toIndexEntry(sorted[anchorIndex]),\n after,\n };\n}\n\n/**\n * Record access for observations returned in search results.\n * Increments accessCount and updates lastAccessedAt.\n * Inspired by mcp-memory-service's record_access() pattern.\n */\nasync function recordAccessBatch(hitDocs: { id: string; doc: MemorixDocument }[]): Promise<void> {\n const database = await getDb();\n const now = new Date().toISOString();\n\n for (const { id, doc } of hitDocs) {\n try {\n // Use update() directly — no need to re-search since we already have the doc\n await update(database, id, {\n ...doc,\n accessCount: (doc.accessCount ?? 0) + 1,\n lastAccessedAt: now,\n });\n } catch {\n // Best-effort — don't break search if access tracking fails\n }\n }\n}\n\n/**\n * Trim search results to fit within a token budget.\n * Inspired by MemCP's _apply_token_budget() pattern.\n */\nfunction applyTokenBudget(entries: IndexEntry[], maxTokens: number): IndexEntry[] {\n const budgeted: IndexEntry[] = [];\n let tokensUsed = 0;\n\n for (const entry of entries) {\n if (tokensUsed + entry.tokens > maxTokens && budgeted.length > 0) {\n break;\n }\n budgeted.push(entry);\n tokensUsed += entry.tokens;\n }\n\n return budgeted;\n}\n\n/**\n * Get total observation count, optionally filtered by project.\n */\nexport async function getObservationCount(projectId?: string): Promise<number> {\n const database = await getDb();\n if (!projectId) {\n return await count(database);\n }\n const results = await search(database, {\n term: '',\n where: { projectId },\n limit: 0,\n });\n return results.count;\n}\n\n/**\n * Format ISO date string to compact time display.\n */\nfunction formatTime(isoDate: string): string {\n try {\n const date = new Date(isoDate);\n return date.toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n });\n } catch {\n return isoDate;\n }\n}\n","/**\n * Token Budget Manager\n *\n * Provides token counting and budget management for Progressive Disclosure.\n * Source: gpt-tokenizer (737 stars, JS port of OpenAI's tiktoken)\n *\n * Used by the Compact Engine to determine which layer of detail\n * fits within the caller's token budget.\n */\n\nimport { countTokens, isWithinTokenLimit } from 'gpt-tokenizer';\n\n/**\n * Count tokens in a string.\n */\nexport function countTextTokens(text: string): number {\n return countTokens(text);\n}\n\n/**\n * Check if text fits within a token limit.\n * Returns the token count if within limit, false otherwise.\n */\nexport function fitsInBudget(text: string, limit: number): number | false {\n return isWithinTokenLimit(text, limit);\n}\n\n/**\n * Truncate text to fit within a token budget.\n * Truncates at sentence boundaries when possible.\n */\nexport function truncateToTokenBudget(text: string, budget: number): string {\n if (fitsInBudget(text, budget) !== false) {\n return text;\n }\n\n // Binary search for the right length\n const sentences = text.split(/(?<=[.!?])\\s+/);\n let result = '';\n\n for (const sentence of sentences) {\n const candidate = result ? `${result} ${sentence}` : sentence;\n if (fitsInBudget(candidate, budget) === false) {\n break;\n }\n result = candidate;\n }\n\n // If no complete sentence fits, truncate by characters\n if (!result) {\n // Rough estimate: 1 token ≈ 4 chars for English, ≈ 1.5 chars for Chinese\n const estimatedChars = budget * 2;\n result = text.slice(0, estimatedChars);\n // Refine\n while (fitsInBudget(result, budget) === false && result.length > 0) {\n result = result.slice(0, Math.floor(result.length * 0.9));\n }\n if (result.length < text.length) {\n result += '...';\n }\n }\n\n return result;\n}\n\n/**\n * Estimate the token cost of an IndexEntry line.\n * Used to predict compact index size.\n */\nexport function estimateIndexEntryTokens(title: string): number {\n // Format: \"| #ID | Time | Icon | Title | ~Tokens |\"\n // Overhead is roughly 15 tokens for formatting\n return countTextTokens(title) + 15;\n}\n","/**\n * Entity Extractor\n *\n * Regex-based entity extraction from observation content.\n * Inspired by MemCP's RegexEntityExtractor (MAGMA paper).\n *\n * Extracts: file paths, module paths, URLs, @mentions, CamelCase identifiers.\n * Also detects causal patterns for automatic edge typing.\n */\n\nconst ENTITY_PATTERNS: Array<{ kind: string; pattern: RegExp }> = [\n // File paths (e.g. src/auth/jwt.ts, ./config.json)\n { kind: 'file', pattern: /(?:^|[\\s\"'(])([.\\w/-]+\\.\\w{1,10})(?:[\\s\"'),]|$)/g },\n // Module/package paths (e.g. @orama/orama, memcp.core.graph)\n { kind: 'module', pattern: /(?:^|[\\s\"'(,])(@[\\w-]+\\/[\\w.-]+)|\\b([a-zA-Z_]\\w*(?:\\.[a-zA-Z_]\\w*){2,})\\b/g },\n // URLs\n { kind: 'url', pattern: /https?:\\/\\/[^\\s\"'<>)]+/g },\n // @mentions\n { kind: 'mention', pattern: /@([a-zA-Z_]\\w+)/g },\n // CamelCase identifiers (likely class/type names)\n { kind: 'identifier', pattern: /\\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\\b/g },\n // Chinese identifiers: quoted Chinese terms or backtick-wrapped Chinese (e.g. 「认证模块」, `数据库连接`)\n { kind: 'identifier', pattern: /[「『【]([一-鿿㐀-䶿]{2,}(?:[一-鿿㐀-䶿a-zA-Z0-9_-]*[一-鿿㐀-䶿])?)[」』】]/g },\n { kind: 'identifier', pattern: /`([一-鿿㐀-䶿]{2,}[一-鿿㐀-䶿a-zA-Z0-9_-]*)`/g },\n];\n\n/**\n * Patterns that indicate causal relationships.\n * Used to auto-detect causal edge types in Knowledge Graph.\n */\nconst CAUSAL_PATTERN = /\\b(?:because|therefore|due to|caused by|as a result|decided to|chosen because|so that|in order to|leads to|results in|fixed by|resolved by)\\b|(?:因为|所以|由于|导致|造成|结果|因此|为了|解决|修复|修正|决定|选择|采用)/i;\n\nexport interface ExtractedEntities {\n files: string[];\n modules: string[];\n urls: string[];\n mentions: string[];\n identifiers: string[];\n hasCausalLanguage: boolean;\n}\n\n/**\n * Extract entities from text content.\n * Returns deduplicated lists of each entity type.\n */\nexport function extractEntities(content: string): ExtractedEntities {\n const result: ExtractedEntities = {\n files: [],\n modules: [],\n urls: [],\n mentions: [],\n identifiers: [],\n hasCausalLanguage: false,\n };\n\n const seen = new Set<string>();\n\n for (const { kind, pattern } of ENTITY_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(content)) !== null) {\n const entity = (match[1] ?? match[2] ?? match[0]).trim().replace(/^[\"'(]+|[\"'),]+$/g, '');\n if (entity.length < 3 || (kind === 'file' && entity.length < 5)) continue;\n\n const key = `${kind}:${entity.toLowerCase()}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n switch (kind) {\n case 'file':\n result.files.push(entity);\n break;\n case 'module':\n result.modules.push(entity);\n break;\n case 'url':\n result.urls.push(entity);\n break;\n case 'mention':\n result.mentions.push(entity);\n break;\n case 'identifier':\n result.identifiers.push(entity);\n break;\n }\n }\n }\n\n result.hasCausalLanguage = CAUSAL_PATTERN.test(content);\n\n return result;\n}\n\n/**\n * Auto-generate concepts from extracted entities.\n * Merges with any user-provided concepts.\n */\nexport function enrichConcepts(\n userConcepts: string[],\n extracted: ExtractedEntities,\n): string[] {\n const all = new Set(userConcepts.map((c) => c.toLowerCase()));\n const enriched = [...userConcepts];\n\n // Add file names (without path) as concepts\n for (const f of extracted.files) {\n const name = f.split('/').pop()?.replace(/\\.\\w+$/, '') ?? '';\n if (name.length >= 3 && !all.has(name.toLowerCase())) {\n all.add(name.toLowerCase());\n enriched.push(name);\n }\n }\n\n // Add module names as concepts\n for (const m of extracted.modules) {\n const short = m.split(/[./]/).pop() ?? '';\n if (short.length >= 3 && !all.has(short.toLowerCase())) {\n all.add(short.toLowerCase());\n enriched.push(short);\n }\n }\n\n // Add CamelCase identifiers as concepts\n for (const id of extracted.identifiers) {\n if (!all.has(id.toLowerCase())) {\n all.add(id.toLowerCase());\n enriched.push(id);\n }\n }\n\n return enriched;\n}\n","/**\n * Observations Manager\n *\n * Manages rich observation records with auto-classification and token counting.\n * Source: claude-mem's observation data model with structured fields.\n *\n * Each observation is stored both in the knowledge graph (as entity observation)\n * and in the Orama search index (for full-text + vector search).\n */\n\nimport type { Observation, ObservationType, ObservationStatus, MemorixDocument, ProgressInfo } from '../types.js';\nimport { TOPIC_KEY_FAMILIES } from '../types.js';\nimport { insertObservation, generateEmbedding, batchGenerateEmbeddings, isEmbeddingEnabled } from '../store/orama-store.js';\nimport { saveObservationsJson, loadObservationsJson, saveIdCounter, loadIdCounter } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\nimport { countTextTokens } from '../compact/token-budget.js';\nimport { extractEntities, enrichConcepts } from './entity-extractor.js';\n\n/** In-memory observation list (loaded from persistence on init) */\nlet observations: Observation[] = [];\nlet nextId = 1;\nlet projectDir: string | null = null;\n\n/**\n * Initialize the observations manager with a project directory.\n */\nexport async function initObservations(dir: string): Promise<void> {\n projectDir = dir;\n const loaded = await loadObservationsJson(dir);\n observations = loaded as Observation[];\n nextId = await loadIdCounter(dir);\n}\n\n/**\n * Store a new observation.\n *\n * This is the primary write API — called by the `memorix_store` MCP tool.\n * Automatically:\n * 1. Assigns an incremental ID\n * 2. Counts tokens for the observation content\n * 3. Inserts into Orama for full-text search\n * 4. Persists to disk\n */\nexport async function storeObservation(input: {\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n concepts?: string[];\n projectId: string;\n topicKey?: string;\n sessionId?: string;\n progress?: ProgressInfo;\n}): Promise<{ observation: Observation; upserted: boolean }> {\n const now = new Date().toISOString();\n\n // Topic key upsert: check if an observation with the same topicKey+projectId exists\n if (input.topicKey) {\n const existing = observations.find(\n o => o.topicKey === input.topicKey && o.projectId === input.projectId,\n );\n if (existing) {\n return { observation: await upsertObservation(existing, input, now), upserted: true };\n }\n }\n\n const id = nextId++;\n\n // Auto-extract entities from narrative (inspired by MemCP RegexEntityExtractor)\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const extracted = extractEntities(contentForExtraction);\n\n // Auto-enrich concepts with extracted entities\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\n\n // Auto-enrich filesModified with extracted file paths\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\n const enrichedFiles = [...(input.filesModified ?? [])];\n for (const f of extracted.files) {\n if (!userFiles.has(f.toLowerCase())) {\n enrichedFiles.push(f);\n }\n }\n\n // Count tokens for the full observation content\n const fullText = [\n input.title,\n input.narrative,\n ...(input.facts ?? []),\n ...enrichedFiles,\n ...enrichedConcepts,\n ].join(' ');\n const tokens = countTextTokens(fullText);\n\n const observation: Observation = {\n id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: input.facts ?? [],\n filesModified: enrichedFiles,\n concepts: enrichedConcepts,\n tokens,\n createdAt: now,\n projectId: input.projectId,\n hasCausalLanguage: extracted.hasCausalLanguage,\n topicKey: input.topicKey,\n revisionCount: 1,\n sessionId: input.sessionId,\n status: 'active',\n progress: input.progress,\n };\n\n observations.push(observation);\n\n // Insert into Orama search index WITHOUT embedding first (non-blocking)\n const doc: MemorixDocument = {\n id: `obs-${id}`,\n observationId: id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: (input.facts ?? []).join('\\n'),\n filesModified: enrichedFiles.join('\\n'),\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens,\n createdAt: now,\n projectId: input.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: 'active',\n };\n\n await insertObservation(doc);\n\n // Persist to disk with file lock (cross-process safe)\n if (projectDir) {\n await withFileLock(projectDir, async () => {\n // Re-read from disk to merge changes from other processes\n const diskObs = await loadObservationsJson(projectDir!) as Observation[];\n const diskNextId = await loadIdCounter(projectDir!);\n\n // Merge: add our new observation if not already present\n const existingIds = new Set(diskObs.map(o => o.id));\n if (!existingIds.has(observation.id)) {\n diskObs.push(observation);\n }\n\n // Use the higher nextId (ours or disk's)\n const mergedNextId = Math.max(nextId, diskNextId);\n\n // Update in-memory state with merged data\n observations = diskObs;\n nextId = mergedNextId;\n\n await saveObservationsJson(projectDir!, observations);\n await saveIdCounter(projectDir!, nextId);\n });\n }\n\n // Generate embedding async (fire-and-forget) — never blocks MCP response\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n generateEmbedding(searchableText).then(async (embedding) => {\n if (embedding) {\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(`obs-${id}`);\n await insertObservation(Object.assign({}, doc, { embedding }));\n } catch {\n // Embedding index update failed — observation still persisted without vector\n }\n }\n }).catch((err) => {\n console.error(`[memorix] Async embedding failed for obs-${id}: ${err instanceof Error ? err.message : err}`);\n });\n\n return { observation, upserted: false };\n}\n\n/**\n * Update an existing observation via topic key upsert.\n * Replaces content but preserves the original ID and createdAt.\n */\nasync function upsertObservation(\n existing: Observation,\n input: {\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n concepts?: string[];\n projectId: string;\n topicKey?: string;\n sessionId?: string;\n progress?: ProgressInfo;\n },\n now: string,\n): Promise<Observation> {\n // Auto-extract and enrich (same as storeObservation)\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const extracted = extractEntities(contentForExtraction);\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\n const enrichedFiles = [...(input.filesModified ?? [])];\n for (const f of extracted.files) {\n if (!userFiles.has(f.toLowerCase())) enrichedFiles.push(f);\n }\n const fullText = [input.title, input.narrative, ...(input.facts ?? []), ...enrichedFiles, ...enrichedConcepts].join(' ');\n const tokens = countTextTokens(fullText);\n\n // Mark old observation as resolved (superseded by new version)\n // Note: topicKey upsert replaces in-place, so we just bump revision\n\n // Update in-place\n existing.entityName = input.entityName;\n existing.type = input.type;\n existing.title = input.title;\n existing.narrative = input.narrative;\n existing.facts = input.facts ?? [];\n existing.filesModified = enrichedFiles;\n existing.concepts = enrichedConcepts;\n existing.tokens = tokens;\n existing.updatedAt = now;\n existing.hasCausalLanguage = extracted.hasCausalLanguage;\n existing.revisionCount = (existing.revisionCount ?? 1) + 1;\n existing.status = 'active';\n if (input.sessionId) existing.sessionId = input.sessionId;\n if (input.progress) existing.progress = input.progress;\n\n // Re-index in Orama WITHOUT embedding first (non-blocking)\n const doc: MemorixDocument = {\n id: `obs-${existing.id}`,\n observationId: existing.id,\n entityName: existing.entityName,\n type: existing.type,\n title: existing.title,\n narrative: existing.narrative,\n facts: existing.facts.join('\\n'),\n filesModified: enrichedFiles.join('\\n'),\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens,\n createdAt: existing.createdAt,\n projectId: existing.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: 'active',\n };\n\n // Remove old doc and insert updated one\n try {\n const { removeObservation } = await import('../store/orama-store.js');\n await removeObservation(`obs-${existing.id}`);\n } catch { /* may not exist in index */ }\n await insertObservation(doc);\n\n // Persist\n if (projectDir) {\n await withFileLock(projectDir, async () => {\n const diskObs = await loadObservationsJson(projectDir!) as Observation[];\n const idx = diskObs.findIndex(o => o.id === existing.id);\n if (idx >= 0) {\n diskObs[idx] = existing;\n } else {\n diskObs.push(existing);\n }\n observations = diskObs;\n await saveObservationsJson(projectDir!, observations);\n });\n }\n\n // Generate embedding async (fire-and-forget) — never blocks MCP response\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const obsId = existing.id;\n generateEmbedding(searchableText).then(async (embedding) => {\n if (embedding) {\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(`obs-${obsId}`);\n await insertObservation(Object.assign({}, doc, { embedding }));\n } catch {\n // Embedding index update failed — observation still persisted without vector\n }\n }\n }).catch((err) => {\n console.error(`[memorix] Async embedding failed for obs-${obsId}: ${err instanceof Error ? err.message : err}`);\n });\n\n return existing;\n}\n\n/**\n * Get an observation by ID.\n */\nexport function getObservation(id: number): Observation | undefined {\n return observations.find((o) => o.id === id);\n}\n\n/**\n * Resolve observations — mark them as resolved (completed/no longer active).\n * This prevents resolved memories from appearing in default search results.\n */\nexport async function resolveObservations(\n ids: number[],\n status: ObservationStatus = 'resolved',\n): Promise<{ resolved: number[]; notFound: number[] }> {\n const resolved: number[] = [];\n const notFound: number[] = [];\n const now = new Date().toISOString();\n\n for (const id of ids) {\n const obs = observations.find(o => o.id === id);\n if (!obs) {\n notFound.push(id);\n continue;\n }\n obs.status = status;\n obs.updatedAt = now;\n if (obs.progress) {\n obs.progress.status = status === 'resolved' ? 'completed' : obs.progress.status;\n }\n resolved.push(id);\n\n // Update Orama index (without blocking on embedding)\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(`obs-${id}`);\n const doc: MemorixDocument = {\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status,\n };\n await insertObservation(doc);\n // Async embedding update (fire-and-forget)\n const obsId = obs.id;\n generateEmbedding([obs.title, obs.narrative, ...obs.facts].join(' ')).then(async (embedding) => {\n if (embedding) {\n try {\n await removeObs(`obs-${obsId}`);\n await insertObservation(Object.assign({}, doc, { embedding }));\n } catch { /* best effort */ }\n }\n }).catch(() => {});\n } catch { /* best effort */ }\n }\n\n // Persist\n if (projectDir && resolved.length > 0) {\n await withFileLock(projectDir, async () => {\n await saveObservationsJson(projectDir!, observations);\n });\n }\n\n return { resolved, notFound };\n}\n\n/**\n * Get all observations for a project.\n * Supports alias expansion: if projectIds is an array, matches any of them.\n */\nexport function getProjectObservations(projectId: string | string[]): Observation[] {\n if (Array.isArray(projectId)) {\n const idSet = new Set(projectId);\n return observations.filter((o) => idSet.has(o.projectId));\n }\n return observations.filter((o) => o.projectId === projectId);\n}\n\n/**\n * Migrate observations from non-canonical project IDs to the canonical ID.\n *\n * Called once during server startup after alias registration.\n * Rewrites in-memory observations and persists changes to disk.\n *\n * @param aliasIds - All known alias IDs for this project (including canonical)\n * @param canonicalId - The canonical project ID to normalize to\n * @returns Number of observations migrated\n */\nexport async function migrateProjectIds(\n aliasIds: string[],\n canonicalId: string,\n): Promise<number> {\n const nonCanonical = new Set(aliasIds.filter(id => id !== canonicalId));\n if (nonCanonical.size === 0) return 0;\n\n let migrated = 0;\n for (const obs of observations) {\n if (nonCanonical.has(obs.projectId)) {\n obs.projectId = canonicalId;\n migrated++;\n }\n }\n\n if (migrated > 0 && projectDir) {\n await withFileLock(projectDir, async () => {\n await saveObservationsJson(projectDir!, observations);\n });\n }\n\n return migrated;\n}\n\n/**\n * Get all observations (in-memory copy).\n * Used by timeline and retention to avoid unreliable Orama empty-term queries.\n */\nexport function getAllObservations(): Observation[] {\n return [...observations];\n}\n\n/**\n * Get the total number of stored observations.\n */\nexport function getObservationCount(): number {\n return observations.length;\n}\n\n/**\n * Suggest a stable topic key from type + title.\n * Uses family heuristics (architecture/*, bug/*, decision/*, etc.)\n * Inspired by Engram's mem_suggest_topic_key.\n */\nexport function suggestTopicKey(type: string, title: string): string {\n // Determine family from type\n let family = 'general';\n const typeLower = type.toLowerCase();\n for (const [fam, keywords] of Object.entries(TOPIC_KEY_FAMILIES)) {\n if (keywords.some(k => typeLower.includes(k))) {\n family = fam;\n break;\n }\n }\n\n // Normalize title to slug\n const slug = title\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, '') // keep letters, digits, CJK, spaces, hyphens\n .trim()\n .replace(/\\s+/g, '-')\n .slice(0, 60);\n\n if (!slug) return '';\n return `${family}/${slug}`;\n}\n\n/**\n * Reload observations into the Orama index.\n * Called during server startup to restore the search index.\n *\n * Optimization: uses batch embedding (ONNX processes 64 texts at a time)\n * instead of individual embed calls. This reduces startup CPU from minutes\n * to seconds for large observation sets (500+).\n */\nexport async function reindexObservations(): Promise<number> {\n if (observations.length === 0) return 0;\n\n // Batch-generate all embeddings at once (much faster than individual calls)\n let embeddings: (number[] | null)[] = [];\n if (isEmbeddingEnabled()) {\n try {\n const texts = observations.map(obs =>\n [obs.title, obs.narrative, ...obs.facts].join(' '),\n );\n embeddings = await batchGenerateEmbeddings(texts);\n } catch {\n // Batch embedding failed — fall back to no embeddings\n }\n }\n\n let count = 0;\n for (let i = 0; i < observations.length; i++) {\n const obs = observations[i];\n try {\n const embedding = embeddings[i] ?? null;\n const doc: MemorixDocument = {\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map((c: string) => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n ...(embedding ? { embedding } : {}),\n };\n await insertObservation(doc);\n count++;\n } catch (err) {\n console.error(`[memorix] Failed to reindex observation #${obs.id}: ${err}`);\n }\n }\n return count;\n}\n","/**\n * Memory Compact Engine\n *\n * Dual-mode memory management inspired by:\n * - Mem0's ADD/UPDATE/DELETE/NONE decision model with content merging\n * - Cipher's dual-mode architecture (LLM + heuristic fallback)\n *\n * Two paths:\n * 1. LLM mode (compactOnWrite): Single LLM call → extract facts + compare + decide + merge\n * 2. Free mode (heuristicCompact): Vector similarity → rule-based ADD/UPDATE/NONE\n *\n * Both paths produce a CompactDecision that the caller executes.\n */\n\nimport { callLLM, isLLMEnabled } from './provider.js';\n\n/** The decision the compact engine makes for each memory operation */\nexport type MemoryAction = 'ADD' | 'UPDATE' | 'DELETE' | 'NONE';\n\n/** Existing memory entry for comparison */\nexport interface ExistingMemory {\n id: number;\n title: string;\n narrative: string;\n facts: string;\n score: number;\n}\n\n/** The compact decision — what to do with the new memory */\nexport interface CompactDecision {\n action: MemoryAction;\n /** ID of existing memory to UPDATE/DELETE */\n targetId?: number;\n /** Brief explanation of why this action was chosen */\n reason: string;\n /** Merged narrative for UPDATE (Mem0-style rewrite) */\n mergedNarrative?: string;\n /** Merged facts for UPDATE */\n mergedFacts?: string[];\n /** LLM-extracted enriched facts (only in LLM mode) */\n enrichedFacts?: string[];\n /** Whether LLM was used for this decision */\n usedLLM: boolean;\n}\n\n/**\n * Unified Compact on Write prompt (Mem0-inspired, single LLM call).\n *\n * This prompt does 3 things in 1 call:\n * 1. Extract structured facts from the new content\n * 2. Compare with existing similar memories\n * 3. Decide ADD/UPDATE/DELETE/NONE and merge if needed\n */\nconst COMPACT_ON_WRITE_PROMPT = `You are a smart coding memory manager. You control the memory of a cross-IDE coding assistant.\n\nYou receive a NEW MEMORY to store and a list of EXISTING similar memories. Your job:\n1. Extract the key facts from the new memory\n2. Compare with existing memories\n3. Decide the best action\n\nActions:\n- ADD: New memory contains unique information. Store it as-is.\n- UPDATE: New memory supersedes or improves an existing one. Merge them into a single, comprehensive memory.\n- DELETE: An existing memory is outdated/contradicted by the new one. Remove it.\n- NONE: New memory is redundant. Existing memories already cover this. Skip storing.\n\nDecision rules:\n- Same topic updated (e.g., \"MySQL → PostgreSQL\"): UPDATE the old memory with merged content\n- Bug fixed that was reported as open: UPDATE the bug report to include the fix\n- Task completed that was tracked as in-progress: UPDATE to mark completed\n- Minor variation of existing memory: NONE (skip)\n- Completely new topic: ADD\n- Old info directly contradicted: DELETE the old one\n- Prefer UPDATE over ADD — keep memory count low, merge information\n\nFor UPDATE: write a merged narrative that combines the best of both old and new, preserving all important details. Also merge the facts lists, removing duplicates.\n\nRespond in JSON only:\n{\n \"action\": \"ADD\" | \"UPDATE\" | \"DELETE\" | \"NONE\",\n \"targetId\": null or existing_memory_id_number,\n \"reason\": \"brief explanation of decision\",\n \"mergedNarrative\": \"merged narrative text (required for UPDATE, null otherwise)\",\n \"mergedFacts\": [\"merged fact 1\", \"merged fact 2\"] or null,\n \"extractedFacts\": [\"fact extracted from new content 1\", \"fact 2\"]\n}`;\n\n// ─── Heuristic Constants (Cipher-inspired) ───────────────────────────\n\n/** Similarity threshold above which we consider memories as \"same topic\" */\nconst SIMILARITY_HIGH = 0.75;\n/** Similarity threshold for \"related but different\" */\nconst SIMILARITY_MEDIUM = 0.5;\n\n// ─── LLM Mode ────────────────────────────────────────────────────────\n\n/**\n * Compact on Write — LLM mode.\n *\n * Single LLM call that extracts facts, compares with existing memories,\n * and decides ADD/UPDATE/DELETE/NONE with merged content.\n *\n * Inspired by Mem0's `get_update_memory_messages` but unified into 1 call.\n */\nexport async function compactOnWrite(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: ExistingMemory[],\n): Promise<CompactDecision> {\n if (!isLLMEnabled()) {\n return heuristicCompact(newMemory, existingMemories);\n }\n\n if (existingMemories.length === 0) {\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\n }\n\n // Build the prompt with new + existing memories (Mem0's temp_uuid_mapping approach)\n const existingList = existingMemories\n .map(m => `[ID: ${m.id}] (similarity: ${m.score.toFixed(2)}) ${m.title}\\n Narrative: ${m.narrative}\\n Facts: ${m.facts}`)\n .join('\\n\\n');\n\n const userMessage = `NEW MEMORY:\nTitle: ${newMemory.title}\nNarrative: ${newMemory.narrative}\nFacts: ${newMemory.facts.join('; ')}\n\nEXISTING SIMILAR MEMORIES:\n${existingList}`;\n\n try {\n const response = await callLLM(COMPACT_ON_WRITE_PROMPT, userMessage);\n\n // Parse response — handle markdown code blocks\n let content = response.content.trim();\n if (content.startsWith('```')) {\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\n }\n\n const parsed = JSON.parse(content) as {\n action: string;\n targetId?: number | null;\n reason?: string;\n mergedNarrative?: string | null;\n mergedFacts?: string[] | null;\n extractedFacts?: string[] | null;\n };\n\n // Validate action\n const action = parsed.action?.toUpperCase() as MemoryAction;\n if (!action || !['ADD', 'UPDATE', 'DELETE', 'NONE'].includes(action)) {\n return { action: 'ADD', reason: 'LLM response invalid, defaulting to ADD', usedLLM: true };\n }\n\n // Validate targetId exists in existing memories for UPDATE/DELETE\n if ((action === 'UPDATE' || action === 'DELETE') && parsed.targetId != null) {\n const targetExists = existingMemories.some(m => m.id === parsed.targetId);\n if (!targetExists) {\n // LLM hallucinated an ID (common issue noted in Mem0's code)\n return { action: 'ADD', reason: `LLM referenced non-existent memory #${parsed.targetId}, defaulting to ADD`, usedLLM: true };\n }\n }\n\n return {\n action,\n targetId: parsed.targetId ?? undefined,\n reason: parsed.reason ?? 'LLM decision',\n mergedNarrative: parsed.mergedNarrative ?? undefined,\n mergedFacts: parsed.mergedFacts ?? undefined,\n enrichedFacts: parsed.extractedFacts ?? undefined,\n usedLLM: true,\n };\n } catch (err) {\n // LLM failed — fall back to heuristic\n console.error(`[memorix] LLM compact failed, falling back to heuristic:`, (err as Error)?.message ?? err);\n return heuristicCompact(newMemory, existingMemories);\n }\n}\n\n// ─── Free Mode (Heuristic) ───────────────────────────────────────────\n\n/**\n * Heuristic Compact — Free mode, no LLM needed.\n *\n * Uses vector similarity scores from search results to make decisions.\n * Inspired by Cipher's fallback logic in extract_and_operate_memory.ts.\n *\n * Decision logic:\n * - score >= 0.75: Very similar → check if new is more complete\n * - New is longer/richer → UPDATE (merge)\n * - Otherwise → NONE (skip, already covered)\n * - score >= 0.50: Related topic\n * - Same entity + same type → UPDATE if new has more facts\n * - Otherwise → ADD (different enough)\n * - score < 0.50: Different topic → ADD\n */\nexport function heuristicCompact(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: ExistingMemory[],\n): CompactDecision {\n if (existingMemories.length === 0) {\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\n }\n\n const best = existingMemories[0]; // Already sorted by score\n\n // High similarity — very likely same topic\n if (best.score >= SIMILARITY_HIGH) {\n const newLength = newMemory.narrative.length + newMemory.facts.join(' ').length;\n const oldLength = best.narrative.length + best.facts.length;\n\n if (newLength > oldLength * 1.2) {\n // New memory is substantially richer — UPDATE with merged content\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\n return {\n action: 'UPDATE',\n targetId: best.id,\n reason: `New memory is more comprehensive (${newLength} > ${oldLength} chars)`,\n mergedNarrative,\n mergedFacts,\n usedLLM: false,\n };\n }\n\n // New memory is not richer — skip it\n return {\n action: 'NONE',\n targetId: best.id,\n reason: `Existing memory #${best.id} already covers this topic (similarity: ${best.score.toFixed(2)})`,\n usedLLM: false,\n };\n }\n\n // Medium similarity — related but might be different enough\n if (best.score >= SIMILARITY_MEDIUM) {\n const newFactCount = newMemory.facts.length;\n const oldFactCount = best.facts.split('\\n').filter(Boolean).length;\n\n if (newFactCount > oldFactCount) {\n // New has more facts — UPDATE\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\n return {\n action: 'UPDATE',\n targetId: best.id,\n reason: `New memory has more facts (${newFactCount} > ${oldFactCount}), merging`,\n mergedNarrative,\n mergedFacts,\n usedLLM: false,\n };\n }\n\n // Related but not richer — ADD as separate memory\n return { action: 'ADD', reason: `Related to #${best.id} but different enough to keep separate`, usedLLM: false };\n }\n\n // Low similarity — new topic\n return { action: 'ADD', reason: 'No similar memories found', usedLLM: false };\n}\n\n// ─── Content Merging Utilities ───────────────────────────────────────\n\n/**\n * Merge two narrative texts, keeping the more comprehensive version\n * while preserving unique information from both.\n */\nfunction mergeTexts(oldText: string, newText: string): string {\n // If new text is significantly longer, prefer it\n if (newText.length > oldText.length * 1.5) return newText;\n // If old text is significantly longer, append new info\n if (oldText.length > newText.length * 1.5) return oldText;\n // Similar length — combine with separator\n return `${newText}\\n\\n[Previous context]: ${oldText}`;\n}\n\n/**\n * Merge two fact lists, removing duplicates.\n * oldFacts is newline-separated string, newFacts is array.\n */\nfunction mergeFacts(oldFactsStr: string, newFactsStr: string): string[] {\n const oldFacts = oldFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\n const newFacts = newFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\n\n const seen = new Set<string>();\n const merged: string[] = [];\n\n // Add new facts first (they're more recent)\n for (const f of newFacts) {\n const normalized = f.toLowerCase();\n if (!seen.has(normalized)) {\n seen.add(normalized);\n merged.push(f);\n }\n }\n\n // Add old facts that aren't duplicates\n for (const f of oldFacts) {\n const normalized = f.toLowerCase();\n if (!seen.has(normalized)) {\n seen.add(normalized);\n merged.push(f);\n }\n }\n\n return merged;\n}\n\n// ─── Batch Dedup (for memorix_deduplicate tool) ──────────────────────\n\n/**\n * LLM-powered dedup for batch cleanup.\n * Compares a new memory against existing ones and returns a decision.\n * Used by memorix_deduplicate tool.\n */\nexport async function deduplicateMemory(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: Array<{ id: number; title: string; narrative: string; facts: string }>,\n): Promise<CompactDecision | null> {\n if (!isLLMEnabled()) return null;\n if (existingMemories.length === 0) return { action: 'ADD', reason: 'No existing memories', usedLLM: false };\n\n const asExisting: ExistingMemory[] = existingMemories.map(m => ({\n ...m,\n score: 0.8, // Batch dedup assumes high similarity (pre-filtered)\n }));\n\n return compactOnWrite(newMemory, asExisting);\n}\n","/**\n * Session Lifecycle Manager\n *\n * Tracks coding sessions across agents and provides context injection\n * for new sessions. Inspired by Engram's session management pattern.\n *\n * Key features:\n * - Start/end session tracking\n * - Structured session summaries (Goal/Discoveries/Accomplished/Files)\n * - Auto-inject previous session context on session start\n * - Cross-agent session awareness (all agents share session data)\n */\n\nimport type { Session, Observation } from '../types.js';\nimport { loadSessionsJson, saveSessionsJson, loadObservationsJson } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\nimport { resolveAliases } from '../project/aliases.js';\n\n/**\n * Resolve a projectId into a Set of all known aliases.\n * Ensures sessions stored under any alias are found regardless of which IDE stored them.\n */\nasync function resolveProjectIds(projectId: string): Promise<Set<string>> {\n try {\n const aliases = await resolveAliases(projectId);\n return new Set(aliases);\n } catch {\n return new Set([projectId]);\n }\n}\n\n/**\n * Generate a unique session ID.\n */\nfunction generateSessionId(): string {\n const ts = Date.now().toString(36);\n const rand = Math.random().toString(36).slice(2, 8);\n return `sess-${ts}-${rand}`;\n}\n\n/**\n * Start a new coding session.\n *\n * Creates a session record and returns context from previous sessions\n * so the agent can resume work without re-explaining everything.\n */\nexport async function startSession(\n projectDir: string,\n projectId: string,\n opts?: { sessionId?: string; agent?: string },\n): Promise<{ session: Session; previousContext: string }> {\n const sessionId = opts?.sessionId || generateSessionId();\n const now = new Date().toISOString();\n\n const session: Session = {\n id: sessionId,\n projectId,\n startedAt: now,\n status: 'active',\n agent: opts?.agent,\n };\n\n // Load previous context before creating new session\n const previousContext = await getSessionContext(projectDir, projectId);\n\n // Persist with file lock\n await withFileLock(projectDir, async () => {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n\n // Mark any existing active sessions as completed (stale)\n const aliasSet = await resolveProjectIds(projectId);\n for (const s of sessions) {\n if (aliasSet.has(s.projectId) && s.status === 'active') {\n s.status = 'completed';\n s.endedAt = now;\n if (!s.summary) {\n s.summary = '(session ended implicitly by new session start)';\n }\n }\n }\n\n sessions.push(session);\n await saveSessionsJson(projectDir, sessions);\n });\n\n return { session, previousContext };\n}\n\n/**\n * End a coding session with an optional structured summary.\n *\n * Summary format (following Engram's convention):\n * ## Goal\n * ## Discoveries\n * ## Accomplished\n * ## Relevant Files\n */\nexport async function endSession(\n projectDir: string,\n sessionId: string,\n summary?: string,\n): Promise<Session | null> {\n let endedSession: Session | null = null;\n\n await withFileLock(projectDir, async () => {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n const session = sessions.find(s => s.id === sessionId);\n\n if (!session) return;\n\n session.status = 'completed';\n session.endedAt = new Date().toISOString();\n if (summary) {\n session.summary = summary;\n }\n\n endedSession = session;\n await saveSessionsJson(projectDir, sessions);\n });\n\n return endedSession;\n}\n\n/**\n * Get formatted context from previous sessions for injection into a new session.\n *\n * Returns a concise summary of:\n * 1. Last completed session's summary (if available)\n * 2. Top observations from recent sessions\n * 3. Active decisions and gotchas\n */\nexport async function getSessionContext(\n projectDir: string,\n projectId: string,\n limit: number = 3,\n): Promise<string> {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n const allObs = await loadObservationsJson(projectDir) as Observation[];\n\n // Get recent completed sessions for this project (newest first)\n const aliasSet = await resolveProjectIds(projectId);\n const projectSessions = sessions\n .filter(s => aliasSet.has(s.projectId) && s.status === 'completed')\n .sort((a, b) => new Date(b.endedAt || b.startedAt).getTime() - new Date(a.endedAt || a.startedAt).getTime())\n .slice(0, limit);\n\n if (projectSessions.length === 0 && allObs.length === 0) {\n return '';\n }\n\n const lines: string[] = [];\n\n // Last session summary\n if (projectSessions.length > 0) {\n const last = projectSessions[0];\n lines.push(`## Previous Session`);\n if (last.agent) {\n lines.push(`Agent: ${last.agent}`);\n }\n lines.push(`Ended: ${last.endedAt || last.startedAt}`);\n if (last.summary && last.summary !== '(session ended implicitly by new session start)') {\n lines.push('');\n lines.push(last.summary);\n }\n lines.push('');\n }\n\n // High-priority recent observations (gotchas, decisions, discoveries)\n const PRIORITY_TYPES = new Set(['gotcha', 'decision', 'problem-solution', 'trade-off', 'discovery']);\n const TYPE_EMOJI: Record<string, string> = {\n 'gotcha': '🔴', 'decision': '🟤', 'problem-solution': '🟡',\n 'trade-off': '⚖️', 'discovery': '🟣', 'how-it-works': '🔵',\n 'what-changed': '🟢', 'why-it-exists': '🟠', 'session-request': '🎯',\n };\n\n const priorityObs = allObs\n .filter(o => aliasSet.has(o.projectId) && PRIORITY_TYPES.has(o.type))\n .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())\n .slice(0, 5);\n\n if (priorityObs.length > 0) {\n lines.push(`## Key Memories`);\n for (const obs of priorityObs) {\n const emoji = TYPE_EMOJI[obs.type] ?? '📌';\n const fact = obs.facts?.[0] ? ` — ${obs.facts[0]}` : '';\n lines.push(`${emoji} ${obs.title}${fact}`);\n }\n lines.push('');\n }\n\n // Session history summary\n if (projectSessions.length > 1) {\n lines.push(`## Session History (last ${projectSessions.length})`);\n for (const s of projectSessions) {\n const date = (s.endedAt || s.startedAt).slice(0, 10);\n const agent = s.agent ? ` [${s.agent}]` : '';\n const summary = s.summary\n ? ` — ${s.summary.split('\\n')[0].replace(/^#+\\s*/, '').slice(0, 80)}`\n : '';\n lines.push(`- ${date}${agent}${summary}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n/**\n * List all sessions for a project.\n */\nexport async function listSessions(\n projectDir: string,\n projectId?: string,\n): Promise<Session[]> {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n if (projectId) {\n const aliasSet = await resolveProjectIds(projectId);\n return sessions.filter(s => aliasSet.has(s.projectId));\n }\n return sessions;\n}\n\n/**\n * Get the currently active session for a project (if any).\n */\nexport async function getActiveSession(\n projectDir: string,\n projectId: string,\n): Promise<Session | null> {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n const aliasSet = await resolveProjectIds(projectId);\n return sessions.find(s => aliasSet.has(s.projectId) && s.status === 'active') || null;\n}\n","/**\n * Retention & Decay Engine\n *\n * Manages memory relevance over time using exponential decay.\n * Sources:\n * - mcp-memory-service: ExponentialDecayCalculator (importance × decay × access_boost)\n * - MemCP: Active → Archive → Purge lifecycle with immunity rules\n *\n * Relevance formula:\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost × connectionBoost\n *\n * Immunity: observations with importance=critical, accessCount>=3, or tagged \"keep\"/\"pinned\"\n * are never auto-archived.\n */\n\nimport type { MemorixDocument, Observation } from '../types.js';\nimport { loadObservationsJson, saveObservationsJson, appendArchivedObservations } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\n// ── Importance → Retention Period mapping ────────────────────────────\n\nexport type ImportanceLevel = 'critical' | 'high' | 'medium' | 'low';\n\nconst RETENTION_DAYS: Record<ImportanceLevel, number> = {\n critical: 365,\n high: 180,\n medium: 90,\n low: 30,\n};\n\nconst BASE_IMPORTANCE: Record<ImportanceLevel, number> = {\n critical: 1.0,\n high: 0.8,\n medium: 0.5,\n low: 0.3,\n};\n\n// ── Observation Type → Default Importance ────────────────────────────\n\nconst TYPE_IMPORTANCE: Record<string, ImportanceLevel> = {\n gotcha: 'high',\n decision: 'high',\n 'trade-off': 'high',\n 'problem-solution': 'medium',\n 'how-it-works': 'medium',\n 'what-changed': 'low',\n 'why-it-exists': 'medium',\n discovery: 'low',\n 'session-request': 'low',\n};\n\n// ── Immunity ─────────────────────────────────────────────────────────\n\nconst PROTECTED_TAGS = new Set(['keep', 'important', 'pinned', 'critical']);\nconst MIN_ACCESS_FOR_IMMUNITY = 3;\n\n/**\n * Check if an observation is immune from archiving/decay.\n * Immune observations maintain a minimum relevance score.\n */\nexport function isImmune(doc: MemorixDocument): boolean {\n const importance = getImportanceLevel(doc);\n if (importance === 'critical' || importance === 'high') return true;\n if ((doc.accessCount ?? 0) >= MIN_ACCESS_FOR_IMMUNITY) return true;\n\n const concepts = doc.concepts?.split(', ').map((c) => c.toLowerCase()) ?? [];\n return concepts.some((c) => PROTECTED_TAGS.has(c));\n}\n\n// ── Relevance Scoring ────────────────────────────────────────────────\n\nexport interface RelevanceScore {\n observationId: number;\n totalScore: number;\n baseImportance: number;\n decayFactor: number;\n accessBoost: number;\n ageDays: number;\n isImmune: boolean;\n}\n\n/**\n * Get the importance level for an observation based on its type.\n */\nexport function getImportanceLevel(doc: MemorixDocument): ImportanceLevel {\n return TYPE_IMPORTANCE[doc.type] ?? 'medium';\n}\n\n/**\n * Calculate the relevance score for a single observation.\n *\n * Formula (from mcp-memory-service):\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost\n *\n * Access boost (from mcp-memory-service):\n * 1 + 0.1 × accessCount (10% boost per access, capped at 2.0)\n */\nexport function calculateRelevance(\n doc: MemorixDocument,\n referenceTime?: Date,\n): RelevanceScore {\n const now = referenceTime ?? new Date();\n const importance = getImportanceLevel(doc);\n const base = BASE_IMPORTANCE[importance];\n const retention = RETENTION_DAYS[importance];\n\n // Age in days\n const createdAt = new Date(doc.createdAt);\n const ageDays = Math.max(0, (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24));\n\n // Exponential decay\n const decayFactor = Math.exp(-ageDays / retention);\n\n // Access boost: 10% per access, capped at 2.0×\n const accessCount = doc.accessCount ?? 0;\n const accessBoost = Math.min(2.0, 1 + 0.1 * accessCount);\n\n let totalScore = base * decayFactor * accessBoost;\n\n // Immune observations get minimum 0.5 relevance\n const immune = isImmune(doc);\n if (immune) {\n totalScore = Math.max(totalScore, 0.5);\n }\n\n return {\n observationId: doc.observationId,\n totalScore,\n baseImportance: base,\n decayFactor,\n accessBoost,\n ageDays,\n isImmune: immune,\n };\n}\n\n/**\n * Score and rank observations by relevance.\n * Returns sorted (highest relevance first) with scores.\n */\nexport function rankByRelevance(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): RelevanceScore[] {\n return docs\n .map((doc) => calculateRelevance(doc, referenceTime))\n .sort((a, b) => b.totalScore - a.totalScore);\n}\n\n// ── Retention Lifecycle ──────────────────────────────────────────────\n\nexport type RetentionZone = 'active' | 'stale' | 'archive-candidate';\n\n/**\n * Classify an observation into a retention zone.\n *\n * Lifecycle (from MemCP):\n * Active: recently accessed or high importance\n * Stale: not accessed, beyond 50% of retention period\n * Archive-candidate: not accessed, beyond 100% of retention period, not immune\n */\nexport function getRetentionZone(doc: MemorixDocument, referenceTime?: Date): RetentionZone {\n const now = referenceTime ?? new Date();\n const importance = getImportanceLevel(doc);\n const retention = RETENTION_DAYS[importance];\n\n const createdAt = new Date(doc.createdAt);\n const ageDays = (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24);\n\n // Recently accessed = active regardless of age\n if (doc.lastAccessedAt) {\n const lastAccess = new Date(doc.lastAccessedAt);\n const daysSinceAccess = (now.getTime() - lastAccess.getTime()) / (1000 * 60 * 60 * 24);\n if (daysSinceAccess < 7) return 'active';\n }\n\n if (isImmune(doc)) return 'active';\n if (ageDays > retention) return 'archive-candidate';\n if (ageDays > retention * 0.5) return 'stale';\n return 'active';\n}\n\n/**\n * Get archive candidates from a list of observations.\n * Returns observations that are beyond their retention period and not immune.\n */\nexport function getArchiveCandidates(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): MemorixDocument[] {\n return docs.filter((doc) => getRetentionZone(doc, referenceTime) === 'archive-candidate');\n}\n\n/**\n * Get retention summary statistics.\n */\nexport function getRetentionSummary(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): { active: number; stale: number; archiveCandidates: number; immune: number } {\n let active = 0;\n let stale = 0;\n let archiveCandidates = 0;\n let immune = 0;\n\n for (const doc of docs) {\n const zone = getRetentionZone(doc, referenceTime);\n if (zone === 'active') active++;\n else if (zone === 'stale') stale++;\n else archiveCandidates++;\n if (isImmune(doc)) immune++;\n }\n\n return { active, stale, archiveCandidates, immune };\n}\n\n// ── Auto-Archive ────────────────────────────────────────────────────\n\n/**\n * Archive expired observations: move archive-candidates from active\n * storage to observations.archived.json.\n *\n * Returns the count of archived observations.\n * Uses file locking for cross-process safety.\n */\nexport async function archiveExpired(\n projectDir: string,\n referenceTime?: Date,\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>,\n): Promise<{ archived: number; remaining: number }> {\n return await withFileLock(projectDir, async () => {\n const allObs = await loadObservationsJson(projectDir) as Observation[];\n\n // Convert to MemorixDocument-like shape for zone calculation\n // Use accessMap (from Orama index) when available for accurate immunity checks\n const toDoc = (obs: Observation): MemorixDocument => {\n const access = accessMap?.get(obs.id);\n return {\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: access?.accessCount ?? 0,\n lastAccessedAt: access?.lastAccessedAt ?? '',\n status: obs.status ?? 'active',\n };\n };\n\n const toArchive: Observation[] = [];\n const toKeep: Observation[] = [];\n\n for (const obs of allObs) {\n const doc = toDoc(obs);\n const zone = getRetentionZone(doc, referenceTime);\n if (zone === 'archive-candidate') {\n toArchive.push(obs);\n } else {\n toKeep.push(obs);\n }\n }\n\n if (toArchive.length === 0) {\n return { archived: 0, remaining: allObs.length };\n }\n\n // Move to archive file, then update active file\n await appendArchivedObservations(projectDir, toArchive);\n await saveObservationsJson(projectDir, toKeep);\n\n return { archived: toArchive.length, remaining: toKeep.length };\n });\n}\n","/**\r\n * Skills Engine — Memory-Driven Project Skills\r\n *\r\n * Memorix's unique take on agent skills:\r\n * - Discovers existing SKILL.md files across all 7 agents\r\n * - Auto-generates project-specific skills from observation patterns\r\n * - Injects skill content directly into agent context (no file reading needed)\r\n *\r\n * Unlike generic skill marketplaces, these skills are derived from YOUR\r\n * project's actual history—decisions, gotchas, patterns, and solutions\r\n * that make this project unique.\r\n *\r\n * SKILL.md format (industry standard):\r\n * ---\r\n * description: Short description for tool use\r\n * ---\r\n * # Skill Title\r\n * Markdown instructions...\r\n */\r\n\r\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport type { AgentTarget, SkillEntry } from '../types.js';\r\n\r\n// ============================================================\r\n// Types\r\n// ============================================================\r\n\r\n/** A skill with full content (for inject/generate) */\r\nexport interface SkillFull extends SkillEntry {\r\n content: string;\r\n /** Whether this was auto-generated from observations */\r\n generated: boolean;\r\n}\r\n\r\n/** Observation data for skill generation */\r\ninterface ObsData {\r\n id: number;\r\n entityName: string;\r\n type: string;\r\n title: string;\r\n narrative: string;\r\n facts?: string[];\r\n concepts?: string[];\r\n filesModified?: string[];\r\n createdAt?: string;\r\n}\r\n\r\n/** Entity cluster for skill generation */\r\ninterface EntityCluster {\r\n entity: string;\r\n observations: ObsData[];\r\n /** Types present in cluster */\r\n types: Set<string>;\r\n /** Score: higher = more skill-worthy */\r\n score: number;\r\n}\r\n\r\n// ============================================================\r\n// Skills Engine\r\n// ============================================================\r\n\r\n/** Skills directories per agent (same as workspace engine) */\r\nconst SKILLS_DIRS: Record<AgentTarget, string[]> = {\r\n codex: ['.codex/skills', '.agents/skills'],\r\n cursor: ['.cursor/skills', '.cursor/skills-cursor'],\r\n windsurf: ['.windsurf/skills'],\r\n 'claude-code': ['.claude/skills'],\r\n copilot: ['.github/skills', '.copilot/skills'],\r\n antigravity: ['.agent/skills', '.gemini/skills', '.gemini/antigravity/skills'],\r\n kiro: ['.kiro/skills'],\r\n opencode: ['.opencode/skills'],\r\n trae: ['.trae/skills'],\r\n};\r\n\r\n/** Types with high signal for skill generation */\r\nconst SKILL_WORTHY_TYPES = new Set([\r\n 'gotcha', 'decision', 'how-it-works', 'problem-solution', 'trade-off',\r\n]);\r\n\r\n/** Minimum observations needed per entity to generate a skill */\r\nconst MIN_OBS_FOR_SKILL = 3;\r\n\r\n/** Minimum score for skill generation */\r\nconst MIN_SCORE_FOR_SKILL = 5;\r\n\r\nexport class SkillsEngine {\r\n private skipGlobal: boolean;\r\n constructor(private projectRoot: string, options?: { skipGlobal?: boolean }) {\r\n this.skipGlobal = options?.skipGlobal ?? false;\r\n }\r\n\r\n // ============================================================\r\n // List: Discover all available skills\r\n // ============================================================\r\n\r\n /**\r\n * List all available skills from all agents + generated suggestions.\r\n */\r\n listSkills(): SkillFull[] {\r\n const skills: SkillFull[] = [];\r\n const seen = new Set<string>();\r\n const home = homedir();\r\n\r\n for (const [agent, dirs] of Object.entries(SKILLS_DIRS)) {\r\n for (const dir of dirs) {\r\n const paths = [join(this.projectRoot, dir)];\r\n if (!this.skipGlobal) {\r\n paths.push(join(home, dir));\r\n }\r\n\r\n for (const skillsRoot of paths) {\r\n if (!existsSync(skillsRoot)) continue;\r\n\r\n try {\r\n const entries = readdirSync(skillsRoot, { withFileTypes: true });\r\n for (const entry of entries) {\r\n if (!entry.isDirectory()) continue;\r\n const name = entry.name;\r\n if (seen.has(name)) continue;\r\n\r\n const skillMd = join(skillsRoot, name, 'SKILL.md');\r\n if (!existsSync(skillMd)) continue;\r\n\r\n try {\r\n const content = readFileSync(skillMd, 'utf-8');\r\n const description = this.parseDescription(content);\r\n\r\n skills.push({\r\n name,\r\n description,\r\n sourcePath: join(skillsRoot, name),\r\n sourceAgent: agent as AgentTarget,\r\n content,\r\n generated: false,\r\n });\r\n seen.add(name);\r\n } catch { /* skip unreadable */ }\r\n }\r\n } catch { /* skip unreadable dirs */ }\r\n }\r\n }\r\n }\r\n\r\n return skills;\r\n }\r\n\r\n // ============================================================\r\n // Generate: Create skills from observation patterns\r\n // ============================================================\r\n\r\n /**\r\n * Analyze observations and generate SKILL.md content for entities with\r\n * rich knowledge accumulation.\r\n */\r\n generateFromObservations(observations: ObsData[]): SkillFull[] {\r\n // 1. Cluster observations by entity\r\n const clusters = this.clusterByEntity(observations);\r\n\r\n // 2. Score each cluster for skill-worthiness\r\n for (const cluster of clusters.values()) {\r\n cluster.score = this.scoreCluster(cluster);\r\n }\r\n\r\n // 3. Generate skills for top clusters\r\n const results: SkillFull[] = [];\r\n const sortedClusters = [...clusters.values()]\r\n .filter(c => c.score >= MIN_SCORE_FOR_SKILL)\r\n .sort((a, b) => b.score - a.score)\r\n .slice(0, 10); // Max 10 auto-generated skills\r\n\r\n for (const cluster of sortedClusters) {\r\n const skill = this.clusterToSkill(cluster);\r\n if (skill) results.push(skill);\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Write a generated skill to the target agent's skills directory.\r\n */\r\n writeSkill(skill: SkillFull, target: AgentTarget): string | null {\r\n const dirs = SKILLS_DIRS[target];\r\n if (!dirs || dirs.length === 0) return null;\r\n\r\n const targetDir = join(this.projectRoot, dirs[0], skill.name);\r\n\r\n try {\r\n mkdirSync(targetDir, { recursive: true });\r\n writeFileSync(join(targetDir, 'SKILL.md'), skill.content, 'utf-8');\r\n return join(dirs[0], skill.name, 'SKILL.md');\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n // ============================================================\r\n // Inject: Return skill content for direct agent consumption\r\n // ============================================================\r\n\r\n /**\r\n * Get full content of a skill by name (for direct injection).\r\n */\r\n injectSkill(name: string): SkillFull | null {\r\n const all = this.listSkills();\r\n return all.find(s => s.name.toLowerCase() === name.toLowerCase()) || null;\r\n }\r\n\r\n // ============================================================\r\n // Internal helpers\r\n // ============================================================\r\n\r\n private parseDescription(content: string): string {\r\n const match = content.match(/^---[\\s\\S]*?description:\\s*[\"']?(.+?)[\"']?\\s*$/m);\r\n return match ? match[1] : '';\r\n }\r\n\r\n private clusterByEntity(observations: ObsData[]): Map<string, EntityCluster> {\r\n const clusters = new Map<string, EntityCluster>();\r\n\r\n for (const obs of observations) {\r\n const entity = obs.entityName || 'unknown';\r\n let cluster = clusters.get(entity);\r\n if (!cluster) {\r\n cluster = { entity, observations: [], types: new Set(), score: 0 };\r\n clusters.set(entity, cluster);\r\n }\r\n cluster.observations.push(obs);\r\n cluster.types.add(obs.type);\r\n }\r\n\r\n return clusters;\r\n }\r\n\r\n private scoreCluster(cluster: EntityCluster): number {\r\n let score = 0;\r\n const obs = cluster.observations;\r\n\r\n // Base: need minimum observations\r\n if (obs.length < MIN_OBS_FOR_SKILL) return 0;\r\n\r\n // Must have at least one skill-worthy type (gotcha/decision/how-it-works/etc.)\r\n let hasSkillWorthyType = false;\r\n for (const type of cluster.types) {\r\n if (SKILL_WORTHY_TYPES.has(type)) {\r\n hasSkillWorthyType = true;\r\n break;\r\n }\r\n }\r\n if (!hasSkillWorthyType) return 0;\r\n\r\n // Volume bonus (1 point per obs, capped at 5)\r\n score += Math.min(obs.length, 5);\r\n\r\n // Type diversity bonus (3 points per unique skill-worthy type)\r\n for (const type of cluster.types) {\r\n if (SKILL_WORTHY_TYPES.has(type)) score += 3;\r\n }\r\n\r\n // Gotcha bonus (critical knowledge that MUST be preserved)\r\n const gotchas = obs.filter(o => o.type === 'gotcha').length;\r\n score += gotchas * 3;\r\n\r\n // Decision bonus (architecture choices that define patterns)\r\n const decisions = obs.filter(o => o.type === 'decision').length;\r\n score += decisions * 2;\r\n\r\n // Facts bonus (structured knowledge)\r\n const totalFacts = obs.reduce((sum, o) => sum + (o.facts?.length || 0), 0);\r\n score += Math.min(totalFacts, 5);\r\n\r\n // Files bonus (indicates real code involvement)\r\n const totalFiles = new Set(obs.flatMap(o => o.filesModified || [])).size;\r\n score += Math.min(totalFiles, 5);\r\n\r\n return score;\r\n }\r\n\r\n private clusterToSkill(cluster: EntityCluster): SkillFull | null {\r\n const { entity, observations } = cluster;\r\n const safeName = entity.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase();\r\n\r\n // Group observations by type\r\n const gotchas = observations.filter(o => o.type === 'gotcha');\r\n const decisions = observations.filter(o => o.type === 'decision');\r\n const howItWorks = observations.filter(o => o.type === 'how-it-works');\r\n const problems = observations.filter(o => o.type === 'problem-solution');\r\n const tradeoffs = observations.filter(o => o.type === 'trade-off');\r\n const others = observations.filter(o =>\r\n !['gotcha', 'decision', 'how-it-works', 'problem-solution', 'trade-off'].includes(o.type),\r\n );\r\n\r\n // Collect all facts and concepts\r\n const allFacts = [...new Set(observations.flatMap(o => o.facts || []))];\r\n const allConcepts = [...new Set(observations.flatMap(o => o.concepts || []))];\r\n const allFiles = [...new Set(observations.flatMap(o => o.filesModified || []))];\r\n\r\n // Build SKILL.md content\r\n const lines: string[] = [];\r\n\r\n // Frontmatter\r\n const description = this.generateDescription(cluster);\r\n lines.push('---');\r\n lines.push(`description: ${description}`);\r\n lines.push('---');\r\n lines.push('');\r\n\r\n // Title\r\n lines.push(`# ${entity}`);\r\n lines.push('');\r\n lines.push(`> Auto-generated from ${observations.length} project observations by Memorix.`);\r\n lines.push('> Adapt to your actual project context before relying on this skill.');\r\n lines.push('');\r\n\r\n // Key files\r\n if (allFiles.length > 0) {\r\n lines.push('## Key Files');\r\n lines.push('');\r\n for (const f of allFiles.slice(0, 15)) {\r\n lines.push(`- \\`${f}\\``);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // Critical gotchas (most important — put first)\r\n if (gotchas.length > 0) {\r\n lines.push('## ⚠️ Critical Gotchas');\r\n lines.push('');\r\n for (const g of gotchas) {\r\n lines.push(`### ${g.title}`);\r\n if (g.narrative) lines.push('', g.narrative);\r\n if (g.facts && g.facts.length > 0) {\r\n lines.push('', ...g.facts.map(f => `- ${f}`));\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Architecture decisions\r\n if (decisions.length > 0) {\r\n lines.push('## 🏗️ Architecture Decisions');\r\n lines.push('');\r\n for (const d of decisions) {\r\n lines.push(`### ${d.title}`);\r\n if (d.narrative) lines.push('', d.narrative);\r\n if (d.facts && d.facts.length > 0) {\r\n lines.push('', ...d.facts.map(f => `- ${f}`));\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // How it works\r\n if (howItWorks.length > 0) {\r\n lines.push('## 📖 How It Works');\r\n lines.push('');\r\n for (const h of howItWorks) {\r\n lines.push(`### ${h.title}`);\r\n if (h.narrative) lines.push('', h.narrative);\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Common problems & solutions\r\n if (problems.length > 0) {\r\n lines.push('## 🔧 Common Problems & Solutions');\r\n lines.push('');\r\n for (const p of problems) {\r\n lines.push(`### ${p.title}`);\r\n if (p.narrative) lines.push('', p.narrative);\r\n if (p.facts && p.facts.length > 0) {\r\n lines.push('', ...p.facts.map(f => `- ${f}`));\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Trade-offs\r\n if (tradeoffs.length > 0) {\r\n lines.push('## ⚖️ Trade-offs');\r\n lines.push('');\r\n for (const t of tradeoffs) {\r\n lines.push(`### ${t.title}`);\r\n if (t.narrative) lines.push('', t.narrative);\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Other notable observations\r\n if (others.length > 0) {\r\n lines.push('## 📝 Notes');\r\n lines.push('');\r\n for (const o of others.slice(0, 5)) {\r\n lines.push(`- **${o.title}**: ${o.narrative?.split('\\n')[0] || ''}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // Key concepts\r\n if (allConcepts.length > 0) {\r\n lines.push('## 🏷️ Related Concepts');\r\n lines.push('');\r\n lines.push(allConcepts.map(c => `\\`${c}\\``).join(', '));\r\n lines.push('');\r\n }\r\n\r\n // Quick facts summary\r\n if (allFacts.length > 0) {\r\n lines.push('## 📌 Quick Facts');\r\n lines.push('');\r\n for (const f of allFacts.slice(0, 15)) {\r\n lines.push(`- ${f}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n const content = lines.join('\\n');\r\n\r\n return {\r\n name: safeName,\r\n description,\r\n sourcePath: '',\r\n sourceAgent: 'codex' as AgentTarget, // generated skills follow SKILL.md standard\r\n content,\r\n generated: true,\r\n };\r\n }\r\n\r\n private generateDescription(cluster: EntityCluster): string {\r\n const parts: string[] = [];\r\n const typeCounts: Record<string, number> = {};\r\n for (const obs of cluster.observations) {\r\n typeCounts[obs.type] = (typeCounts[obs.type] || 0) + 1;\r\n }\r\n\r\n if (typeCounts['gotcha']) parts.push(`${typeCounts['gotcha']} gotcha(s)`);\r\n if (typeCounts['decision']) parts.push(`${typeCounts['decision']} decision(s)`);\r\n if (typeCounts['how-it-works']) parts.push(`${typeCounts['how-it-works']} explanation(s)`);\r\n if (typeCounts['problem-solution']) parts.push(`${typeCounts['problem-solution']} fix(es)`);\r\n\r\n const summary = parts.length > 0 ? parts.join(', ') : `${cluster.observations.length} observations`;\r\n return `Project patterns for ${cluster.entity}: ${summary}`;\r\n }\r\n}\r\n","/**\n * Mini-Skills Engine — Promoted memories that never decay\n *\n * Converts important observations into permanent, actionable \"mini-skills\"\n * that are automatically injected into agent context during session_start.\n *\n * Unlike generic SKILL.md files from marketplaces, mini-skills are:\n * - Derived from YOUR project's actual memories (gotchas, decisions, fixes)\n * - Immune from retention decay (permanent knowledge)\n * - Auto-injected at session start (agents proactively apply them)\n * - Cross-IDE shared (stored in ~/.memorix/data/ alongside observations)\n *\n * Lifecycle: observation → memorix_promote → mini-skill → session_start injection\n */\n\nimport type { MiniSkill, Observation } from '../types.js';\nimport {\n loadMiniSkillsJson,\n saveMiniSkillsJson,\n loadMiniSkillsCounter,\n saveMiniSkillsCounter,\n} from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\n// ── Promote observations to mini-skills ──────────────────────────\n\nexport interface PromoteOptions {\n /** Override auto-generated trigger description */\n trigger?: string;\n /** Override auto-generated instruction */\n instruction?: string;\n /** Extra tags */\n tags?: string[];\n}\n\n/**\n * Promote one or more observations into a mini-skill.\n * The source observations are NOT deleted — they remain in the observation store\n * but the mini-skill is the permanent, never-decaying version.\n */\nexport async function promoteToMiniSkill(\n projectDir: string,\n projectId: string,\n observations: Observation[],\n options?: PromoteOptions,\n): Promise<MiniSkill> {\n return await withFileLock(projectDir, async () => {\n const existing = (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n let nextId = await loadMiniSkillsCounter(projectDir);\n\n // Auto-generate content from observations\n const title = generateTitle(observations);\n const instruction = options?.instruction || generateInstruction(observations);\n const trigger = options?.trigger || generateTrigger(observations);\n const facts = extractFacts(observations);\n const tags = [\n ...(options?.tags || []),\n ...extractTags(observations),\n ];\n\n const skill: MiniSkill = {\n id: nextId,\n sourceObservationIds: observations.map(o => o.id),\n sourceEntity: observations[0]?.entityName || 'unknown',\n title,\n instruction,\n trigger,\n facts,\n projectId,\n createdAt: new Date().toISOString(),\n usedCount: 0,\n tags: [...new Set(tags)],\n };\n\n existing.push(skill);\n nextId++;\n\n await saveMiniSkillsJson(projectDir, existing);\n await saveMiniSkillsCounter(projectDir, nextId);\n\n return skill;\n });\n}\n\n// ── Load & query mini-skills ─────────────────────────────────────\n\n/**\n * Load all mini-skills for a project.\n */\nexport async function loadMiniSkills(\n projectDir: string,\n projectId?: string,\n): Promise<MiniSkill[]> {\n const all = (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n if (!projectId) return all;\n return all.filter(s => s.projectId === projectId);\n}\n\n/**\n * Load all mini-skills (unfiltered).\n */\nexport async function loadAllMiniSkills(projectDir: string): Promise<MiniSkill[]> {\n return (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n}\n\n/**\n * Delete a mini-skill by ID.\n */\nexport async function deleteMiniSkill(\n projectDir: string,\n skillId: number,\n): Promise<boolean> {\n return await withFileLock(projectDir, async () => {\n const existing = (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n const idx = existing.findIndex(s => s.id === skillId);\n if (idx === -1) return false;\n existing.splice(idx, 1);\n await saveMiniSkillsJson(projectDir, existing);\n return true;\n });\n}\n\n/**\n * Increment usedCount for skills that were injected in session_start.\n */\nexport async function recordMiniSkillUsage(\n projectDir: string,\n skillIds: number[],\n): Promise<void> {\n if (skillIds.length === 0) return;\n await withFileLock(projectDir, async () => {\n const existing = (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n for (const skill of existing) {\n if (skillIds.includes(skill.id)) {\n skill.usedCount++;\n }\n }\n await saveMiniSkillsJson(projectDir, existing);\n });\n}\n\n// ── Format mini-skills for session injection ─────────────────────\n\n/**\n * Format mini-skills for injection into session_start context.\n * Returns a markdown string ready to append to session context.\n */\nexport function formatMiniSkillsForInjection(skills: MiniSkill[]): string {\n if (skills.length === 0) return '';\n\n const lines = [\n `## 🎯 Project Mini-Skills (${skills.length} active)`,\n '',\n ];\n\n for (const skill of skills) {\n lines.push(`### ${skill.title}`);\n lines.push(`**Do**: ${skill.instruction}`);\n lines.push(`**When**: ${skill.trigger}`);\n if (skill.facts.length > 0) {\n for (const fact of skill.facts) {\n lines.push(`- ${fact}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── Auto-generation helpers ──────────────────────────────────────\n\nfunction generateTitle(observations: Observation[]): string {\n if (observations.length === 1) {\n return observations[0].title;\n }\n // Multiple observations — use the first one's title as base\n return observations[0].title;\n}\n\nfunction generateInstruction(observations: Observation[]): string {\n // Convert narrative into imperative instruction\n const obs = observations[0];\n const narrative = obs.narrative || '';\n\n // For gotchas, flip to \"avoid\" instruction\n if (obs.type === 'gotcha') {\n return `Avoid: ${narrative.split('\\n')[0]}`;\n }\n // For decisions, state the chosen approach\n if (obs.type === 'decision') {\n return `Follow: ${narrative.split('\\n')[0]}`;\n }\n // For problem-solution, state the solution\n if (obs.type === 'problem-solution') {\n return `Apply fix: ${narrative.split('\\n')[0]}`;\n }\n // Default: use narrative as-is\n return narrative.split('\\n')[0] || obs.title;\n}\n\nfunction generateTrigger(observations: Observation[]): string {\n const obs = observations[0];\n\n // Use entity name + file paths as trigger context\n const parts: string[] = [];\n if (obs.entityName && obs.entityName !== 'unknown') {\n parts.push(`Working on ${obs.entityName}`);\n }\n if (obs.filesModified.length > 0) {\n parts.push(`touching ${obs.filesModified.slice(0, 3).join(', ')}`);\n }\n if (obs.concepts.length > 0) {\n parts.push(`involving ${obs.concepts.slice(0, 3).join(', ')}`);\n }\n\n return parts.length > 0 ? parts.join('; ') : `Related to ${obs.title}`;\n}\n\nfunction extractFacts(observations: Observation[]): string[] {\n const facts = new Set<string>();\n for (const obs of observations) {\n for (const f of obs.facts) {\n facts.add(f);\n }\n }\n return [...facts].slice(0, 10);\n}\n\nfunction extractTags(observations: Observation[]): string[] {\n const tags = new Set<string>();\n for (const obs of observations) {\n tags.add(obs.type);\n for (const c of obs.concepts) {\n if (c.length <= 30) tags.add(c.toLowerCase());\n }\n }\n return [...tags].slice(0, 10);\n}\n","/**\n * Memory Consolidation Engine\n *\n * Merges similar observations into consolidated summaries to prevent data bloat.\n * Uses text similarity (Jaccard on token n-grams) to find clusters of related\n * observations, then merges them into a single observation preserving key facts.\n *\n * Strategy:\n * 1. Group observations by entity + type\n * 2. Within each group, compute pairwise similarity\n * 3. Cluster observations above a similarity threshold\n * 4. Merge each cluster into a consolidated observation\n * 5. Remove originals, keep the merged result\n *\n * Inspired by Engram's duplicate_count and MemCP's MAGMA consolidation.\n */\n\nimport type { Observation } from '../types.js';\nimport { loadObservationsJson, saveObservationsJson } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\n/** Default similarity threshold for merging (0.0-1.0) */\nconst DEFAULT_SIMILARITY_THRESHOLD = 0.45;\n\n/** Minimum cluster size to trigger consolidation */\nconst MIN_CLUSTER_SIZE = 2;\n\n/** Maximum observations to process in one consolidation run */\nconst MAX_BATCH_SIZE = 500;\n\n/**\n * Tokenize text into word-level tokens for similarity comparison.\n */\nfunction tokenize(text: string): Set<string> {\n return new Set(\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, ' ')\n .split(/\\s+/)\n .filter(t => t.length > 1),\n );\n}\n\n/**\n * Compute Jaccard similarity between two sets of tokens.\n */\nfunction jaccardSimilarity(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 && b.size === 0) return 1;\n let intersection = 0;\n for (const token of a) {\n if (b.has(token)) intersection++;\n }\n const union = a.size + b.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\n/**\n * Build a text fingerprint from an observation for similarity matching.\n */\nfunction observationFingerprint(obs: Observation): string {\n return [obs.title, obs.narrative, ...obs.facts, ...obs.concepts].join(' ');\n}\n\n/** A cluster of similar observations to be merged */\nexport interface ConsolidationCluster {\n /** IDs of observations in this cluster */\n ids: number[];\n /** Titles of observations in this cluster */\n titles: string[];\n /** Average pairwise similarity */\n similarity: number;\n /** The entity these belong to */\n entityName: string;\n /** The observation type */\n type: string;\n}\n\n/** Result of a consolidation run */\nexport interface ConsolidationResult {\n /** Number of clusters found */\n clustersFound: number;\n /** Number of observations merged */\n observationsMerged: number;\n /** Number of observations after consolidation */\n observationsAfter: number;\n /** Details of each merge */\n merges: Array<{\n clusterId: number;\n mergedIds: number[];\n resultTitle: string;\n factCount: number;\n }>;\n}\n\n/**\n * Find clusters of similar observations that could be consolidated.\n * Does NOT modify data — use this for preview / dry run.\n */\nexport async function findConsolidationCandidates(\n projectDir: string,\n projectId: string,\n opts?: { threshold?: number; limit?: number },\n): Promise<ConsolidationCluster[]> {\n const threshold = opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD;\n const limit = opts?.limit ?? MAX_BATCH_SIZE;\n\n const allObs = (await loadObservationsJson(projectDir)) as Observation[];\n const projectObs = allObs\n .filter(o => o.projectId === projectId)\n .slice(0, limit);\n\n if (projectObs.length < MIN_CLUSTER_SIZE) return [];\n\n // Group by entity + type\n const groups = new Map<string, Observation[]>();\n for (const obs of projectObs) {\n const key = `${obs.entityName}::${obs.type}`;\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(obs);\n }\n\n const clusters: ConsolidationCluster[] = [];\n\n for (const [, group] of groups) {\n if (group.length < MIN_CLUSTER_SIZE) continue;\n\n // Pre-compute fingerprints\n const fingerprints = group.map(obs => ({\n obs,\n tokens: tokenize(observationFingerprint(obs)),\n }));\n\n // Track which observations are already clustered\n const clustered = new Set<number>();\n\n // Greedy clustering: for each unclustered obs, find similar ones\n for (let i = 0; i < fingerprints.length; i++) {\n if (clustered.has(fingerprints[i].obs.id)) continue;\n\n const cluster: Observation[] = [fingerprints[i].obs];\n let totalSim = 0;\n let simCount = 0;\n\n for (let j = i + 1; j < fingerprints.length; j++) {\n if (clustered.has(fingerprints[j].obs.id)) continue;\n\n const sim = jaccardSimilarity(fingerprints[i].tokens, fingerprints[j].tokens);\n if (sim >= threshold) {\n cluster.push(fingerprints[j].obs);\n totalSim += sim;\n simCount++;\n }\n }\n\n if (cluster.length >= MIN_CLUSTER_SIZE) {\n for (const obs of cluster) clustered.add(obs.id);\n clusters.push({\n ids: cluster.map(o => o.id),\n titles: cluster.map(o => o.title),\n similarity: simCount > 0 ? totalSim / simCount : 0,\n entityName: cluster[0].entityName,\n type: cluster[0].type,\n });\n }\n }\n }\n\n return clusters;\n}\n\n/**\n * Execute consolidation — merge clusters into single observations.\n *\n * For each cluster:\n * 1. Keep the most recent observation as the \"primary\"\n * 2. Merge facts, files, concepts from all members (deduplicated)\n * 3. Create a consolidated narrative\n * 4. Remove the other members\n */\nexport async function executeConsolidation(\n projectDir: string,\n projectId: string,\n opts?: { threshold?: number; limit?: number },\n): Promise<ConsolidationResult> {\n const clusters = await findConsolidationCandidates(projectDir, projectId, opts);\n\n if (clusters.length === 0) {\n const allObs = (await loadObservationsJson(projectDir)) as Observation[];\n return {\n clustersFound: 0,\n observationsMerged: 0,\n observationsAfter: allObs.filter(o => o.projectId === projectId).length,\n merges: [],\n };\n }\n\n const result: ConsolidationResult = {\n clustersFound: clusters.length,\n observationsMerged: 0,\n observationsAfter: 0,\n merges: [],\n };\n\n await withFileLock(projectDir, async () => {\n const allObs = (await loadObservationsJson(projectDir)) as Observation[];\n const obsMap = new Map(allObs.map(o => [o.id, o]));\n const idsToRemove = new Set<number>();\n\n for (let ci = 0; ci < clusters.length; ci++) {\n const cluster = clusters[ci];\n const members = cluster.ids\n .map(id => obsMap.get(id))\n .filter((o): o is Observation => o !== undefined);\n\n if (members.length < MIN_CLUSTER_SIZE) continue;\n\n // Sort by date — most recent first\n members.sort((a, b) =>\n new Date(b.updatedAt || b.createdAt).getTime() -\n new Date(a.updatedAt || a.createdAt).getTime(),\n );\n\n const primary = members[0];\n const others = members.slice(1);\n\n // Merge facts (deduplicated)\n const allFacts = new Set(primary.facts);\n for (const other of others) {\n for (const fact of other.facts) allFacts.add(fact);\n }\n\n // Merge files (deduplicated, case-insensitive)\n const fileSet = new Set(primary.filesModified.map(f => f.toLowerCase()));\n const allFiles = [...primary.filesModified];\n for (const other of others) {\n for (const f of other.filesModified) {\n if (!fileSet.has(f.toLowerCase())) {\n fileSet.add(f.toLowerCase());\n allFiles.push(f);\n }\n }\n }\n\n // Merge concepts (deduplicated)\n const conceptSet = new Set(primary.concepts);\n for (const other of others) {\n for (const c of other.concepts) conceptSet.add(c);\n }\n\n // Build consolidated narrative\n const narrativeParts = [primary.narrative];\n for (const other of others) {\n if (other.narrative !== primary.narrative) {\n narrativeParts.push(`[Consolidated from #${other.id}] ${other.narrative}`);\n }\n }\n\n // Update primary\n primary.facts = [...allFacts];\n primary.filesModified = allFiles;\n primary.concepts = [...conceptSet];\n primary.narrative = narrativeParts.join('\\n\\n');\n primary.updatedAt = new Date().toISOString();\n primary.revisionCount = (primary.revisionCount ?? 1) + others.length;\n\n // Mark others for removal\n for (const other of others) {\n idsToRemove.add(other.id);\n }\n\n result.observationsMerged += others.length;\n result.merges.push({\n clusterId: ci,\n mergedIds: cluster.ids,\n resultTitle: primary.title,\n factCount: primary.facts.length,\n });\n }\n\n // Remove merged observations\n const remaining = allObs.filter(o => !idsToRemove.has(o.id));\n await saveObservationsJson(projectDir, remaining);\n\n result.observationsAfter = remaining.filter(o => o.projectId === projectId).length;\n });\n\n return result;\n}\n","/**\n * Export/Import Engine\n *\n * Enables team collaboration by exporting and importing Memorix data.\n *\n * Export formats:\n * - JSON: Full fidelity, machine-readable\n * - Markdown: Human-readable, great for sharing in PRs/docs\n *\n * Import: JSON format only (full fidelity restore)\n */\n\nimport type { Observation } from '../types.js';\nimport type { Session } from '../types.js';\nimport { loadObservationsJson, saveObservationsJson, loadIdCounter, saveIdCounter } from '../store/persistence.js';\nimport { loadSessionsJson, saveSessionsJson } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\n/** Export package structure */\nexport interface MemorixExport {\n version: string;\n exportedAt: string;\n projectId: string;\n observations: Observation[];\n sessions: Session[];\n stats: {\n observationCount: number;\n sessionCount: number;\n typeBreakdown: Record<string, number>;\n };\n}\n\nconst OBSERVATION_ICONS: Record<string, string> = {\n 'session-request': '🎯', 'gotcha': '🔴', 'problem-solution': '🟡',\n 'how-it-works': '🔵', 'what-changed': '🟢', 'discovery': '🟣',\n 'why-it-exists': '🟠', 'decision': '🟤', 'trade-off': '⚖️',\n};\n\n/**\n * Export project data as JSON.\n */\nexport async function exportAsJson(\n projectDir: string,\n projectId: string,\n): Promise<MemorixExport> {\n const allObs = (await loadObservationsJson(projectDir)) as Observation[];\n const allSessions = (await loadSessionsJson(projectDir)) as Session[];\n\n const projectObs = allObs.filter(o => o.projectId === projectId);\n const projectSessions = allSessions.filter(s => s.projectId === projectId);\n\n // Type breakdown\n const typeBreakdown: Record<string, number> = {};\n for (const obs of projectObs) {\n typeBreakdown[obs.type] = (typeBreakdown[obs.type] ?? 0) + 1;\n }\n\n return {\n version: '0.9.0',\n exportedAt: new Date().toISOString(),\n projectId,\n observations: projectObs,\n sessions: projectSessions,\n stats: {\n observationCount: projectObs.length,\n sessionCount: projectSessions.length,\n typeBreakdown,\n },\n };\n}\n\n/**\n * Export project data as human-readable Markdown.\n */\nexport async function exportAsMarkdown(\n projectDir: string,\n projectId: string,\n): Promise<string> {\n const data = await exportAsJson(projectDir, projectId);\n const lines: string[] = [];\n\n lines.push(`# Memorix Export: ${projectId}`);\n lines.push(`Exported: ${data.exportedAt}`);\n lines.push(`Observations: ${data.stats.observationCount} | Sessions: ${data.stats.sessionCount}`);\n lines.push('');\n\n // Type breakdown\n if (Object.keys(data.stats.typeBreakdown).length > 0) {\n lines.push('## Type Distribution');\n for (const [type, count] of Object.entries(data.stats.typeBreakdown).sort((a, b) => b[1] - a[1])) {\n const icon = OBSERVATION_ICONS[type] ?? '❓';\n lines.push(`- ${icon} ${type}: ${count}`);\n }\n lines.push('');\n }\n\n // Sessions\n if (data.sessions.length > 0) {\n lines.push('## Sessions');\n for (const s of data.sessions) {\n const status = s.status === 'active' ? '🟢' : '✅';\n const agent = s.agent ? ` [${s.agent}]` : '';\n lines.push(`### ${status} ${s.id}${agent}`);\n lines.push(`Started: ${s.startedAt}${s.endedAt ? ` | Ended: ${s.endedAt}` : ''}`);\n if (s.summary) {\n lines.push('');\n lines.push(s.summary);\n }\n lines.push('');\n }\n }\n\n // Observations grouped by entity\n const byEntity = new Map<string, Observation[]>();\n for (const obs of data.observations) {\n if (!byEntity.has(obs.entityName)) byEntity.set(obs.entityName, []);\n byEntity.get(obs.entityName)!.push(obs);\n }\n\n lines.push('## Observations');\n for (const [entity, observations] of byEntity) {\n lines.push(`### ${entity}`);\n for (const obs of observations) {\n const icon = OBSERVATION_ICONS[obs.type] ?? '❓';\n lines.push(`#### ${icon} #${obs.id} ${obs.title}`);\n lines.push(`Type: ${obs.type} | Created: ${obs.createdAt}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ''}${obs.revisionCount && obs.revisionCount > 1 ? ` | Rev: ${obs.revisionCount}` : ''}`);\n lines.push('');\n lines.push(obs.narrative);\n if (obs.facts.length > 0) {\n lines.push('');\n lines.push('**Facts:**');\n for (const f of obs.facts) lines.push(`- ${f}`);\n }\n if (obs.filesModified.length > 0) {\n lines.push('');\n lines.push(`**Files:** ${obs.filesModified.join(', ')}`);\n }\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Import observations and sessions from a JSON export.\n * Re-assigns IDs to avoid conflicts with existing data.\n */\nexport async function importFromJson(\n projectDir: string,\n data: MemorixExport,\n): Promise<{ observationsImported: number; sessionsImported: number; skipped: number }> {\n let imported = 0;\n let sessionsImported = 0;\n let skipped = 0;\n\n await withFileLock(projectDir, async () => {\n const existingObs = (await loadObservationsJson(projectDir)) as Observation[];\n const existingSessions = (await loadSessionsJson(projectDir)) as Session[];\n let nextId = await loadIdCounter(projectDir);\n\n // Build set of existing topicKey+projectId for dedup\n const existingTopicKeys = new Set(\n existingObs\n .filter(o => o.topicKey)\n .map(o => `${o.projectId}::${o.topicKey}`),\n );\n\n // Import observations\n for (const obs of data.observations) {\n // Skip if topicKey already exists (dedup)\n if (obs.topicKey && existingTopicKeys.has(`${obs.projectId}::${obs.topicKey}`)) {\n skipped++;\n continue;\n }\n\n const newObs = { ...obs, id: nextId++ };\n existingObs.push(newObs);\n imported++;\n }\n\n // Import sessions (skip duplicates by ID)\n const existingSessionIds = new Set(existingSessions.map(s => s.id));\n for (const session of data.sessions) {\n if (!existingSessionIds.has(session.id)) {\n existingSessions.push(session);\n sessionsImported++;\n }\n }\n\n await saveObservationsJson(projectDir, existingObs);\n await saveIdCounter(projectDir, nextId);\n await saveSessionsJson(projectDir, existingSessions);\n });\n\n return { observationsImported: imported, sessionsImported, skipped };\n}\n","/**\r\n * Memorix Dashboard Server\r\n *\r\n * Lightweight HTTP server that serves:\r\n * - REST API endpoints for reading memorix data\r\n * - Static frontend files (SPA)\r\n *\r\n * Zero external dependencies — uses Node.js built-in http module.\r\n */\r\n\r\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport { exec } from 'node:child_process';\r\n\r\nimport { loadGraphJsonl, saveGraphJsonl, loadObservationsJson, saveObservationsJson, loadIdCounter, getBaseDataDir, loadSessionsJson } from '../store/persistence.js';\r\nimport { withFileLock } from '../store/file-lock.js';\r\n\r\n// MIME types for static file serving\r\nconst MIME_TYPES: Record<string, string> = {\r\n '.html': 'text/html; charset=utf-8',\r\n '.css': 'text/css; charset=utf-8',\r\n '.js': 'application/javascript; charset=utf-8',\r\n '.json': 'application/json; charset=utf-8',\r\n '.svg': 'image/svg+xml',\r\n '.png': 'image/png',\r\n '.ico': 'image/x-icon',\r\n};\r\n\r\n/**\r\n * Send a JSON response\r\n */\r\nfunction sendJson(res: ServerResponse, data: unknown, status = 200) {\r\n res.writeHead(status, {\r\n 'Content-Type': 'application/json; charset=utf-8',\r\n 'Access-Control-Allow-Origin': '*',\r\n });\r\n res.end(JSON.stringify(data));\r\n}\r\n\r\n/**\r\n * Send an error response\r\n */\r\nfunction sendError(res: ServerResponse, message: string, status = 500) {\r\n sendJson(res, { error: message }, status);\r\n}\r\n\r\n/**\r\n * Filter observations by projectId\r\n */\r\nfunction filterByProject<T extends { projectId?: string }>(items: T[], projectId: string): T[] {\r\n return items.filter(item => item.projectId === projectId);\r\n}\r\n\r\n/**\r\n * API route handlers\r\n */\r\nasync function handleApi(\r\n req: IncomingMessage,\r\n res: ServerResponse,\r\n dataDir: string,\r\n projectId: string,\r\n projectName: string,\r\n baseDir: string,\r\n) {\r\n const url = new URL(req.url || '/', `http://${req.headers.host}`);\r\n const apiPath = url.pathname.replace('/api', '');\r\n\r\n // Support ?project=xxx to switch view to another project\r\n // In flat storage, all projects share the same dataDir — only the projectId filter changes\r\n const requestedProject = url.searchParams.get('project');\r\n let effectiveDataDir = dataDir;\r\n let effectiveProjectId = projectId;\r\n let effectiveProjectName = projectName;\r\n if (requestedProject && requestedProject !== projectId) {\r\n effectiveDataDir = baseDir; // flat storage: all data in one dir\r\n effectiveProjectId = requestedProject;\r\n effectiveProjectName = requestedProject.split('/').pop() || requestedProject;\r\n }\r\n\r\n try {\r\n switch (apiPath) {\r\n case '/projects': {\r\n // List all unique project IDs from observations data (flat storage)\r\n // Deduplicate using alias registry — aliased IDs are merged under canonical\r\n try {\r\n const allObs = await loadObservationsJson(baseDir) as Array<{ projectId?: string }>;\r\n const projectSet = new Map<string, number>();\r\n for (const obs of allObs) {\r\n if (obs.projectId) {\r\n projectSet.set(obs.projectId, (projectSet.get(obs.projectId) || 0) + 1);\r\n }\r\n }\r\n\r\n // Merge aliased project IDs into their canonical form\r\n let mergedSet = projectSet;\r\n try {\r\n const { getCanonicalId } = await import('../project/aliases.js');\r\n mergedSet = new Map<string, number>();\r\n for (const [id, count] of projectSet) {\r\n const canonical = await getCanonicalId(id);\r\n mergedSet.set(canonical, (mergedSet.get(canonical) || 0) + count);\r\n }\r\n } catch { /* alias module not available, use raw IDs */ }\r\n\r\n const projects = Array.from(mergedSet.entries())\r\n .sort((a, b) => b[1] - a[1]) // Most observations first\r\n .map(([id, count]) => ({\r\n id,\r\n name: id.split('/').pop() || id,\r\n count,\r\n isCurrent: id === projectId,\r\n }));\r\n sendJson(res, projects);\r\n } catch {\r\n sendJson(res, []);\r\n }\r\n break;\r\n }\r\n\r\n case '/project': {\r\n sendJson(res, { id: effectiveProjectId, name: effectiveProjectName });\r\n break;\r\n }\r\n\r\n case '/graph': {\r\n const graph = await loadGraphJsonl(effectiveDataDir);\r\n sendJson(res, graph);\r\n break;\r\n }\r\n\r\n case '/observations': {\r\n const allObs = await loadObservationsJson(effectiveDataDir);\r\n const observations = filterByProject(allObs as Array<{ projectId?: string }>, effectiveProjectId);\r\n sendJson(res, observations);\r\n break;\r\n }\r\n\r\n case '/sessions': {\r\n const allSessions = await loadSessionsJson(effectiveDataDir);\r\n const sessions = filterByProject(allSessions as Array<{ projectId?: string }>, effectiveProjectId);\r\n sendJson(res, sessions);\r\n break;\r\n }\r\n\r\n case '/stats': {\r\n const graph = await loadGraphJsonl(effectiveDataDir);\r\n const allObs = await loadObservationsJson(effectiveDataDir);\r\n const observations = filterByProject(allObs as Array<{ projectId?: string; type?: string; id?: number; createdAt?: string; title?: string; entityName?: string }>, effectiveProjectId);\r\n const nextId = await loadIdCounter(effectiveDataDir);\r\n\r\n // Type counts\r\n const typeCounts: Record<string, number> = {};\r\n for (const obs of observations) {\r\n const t = obs.type || 'unknown';\r\n typeCounts[t] = (typeCounts[t] || 0) + 1;\r\n }\r\n\r\n // Recent observations (last 10)\r\n const sorted = [...observations]\r\n .sort((a, b) => (b.id || 0) - (a.id || 0))\r\n .slice(0, 10);\r\n\r\n // Embedding provider status\r\n let embeddingStatus = { enabled: false, provider: '', dimensions: 0 };\r\n try {\r\n const { getEmbeddingProvider } = await import('../embedding/provider.js');\r\n const embProvider = await getEmbeddingProvider();\r\n embeddingStatus = {\r\n enabled: embProvider !== null,\r\n provider: embProvider?.name || '',\r\n dimensions: embProvider?.dimensions || 0,\r\n };\r\n } catch { /* embedding module not available */ }\r\n\r\n sendJson(res, {\r\n entities: graph.entities.length,\r\n relations: graph.relations.length,\r\n observations: observations.length,\r\n nextId,\r\n typeCounts,\r\n recentObservations: sorted,\r\n embedding: embeddingStatus,\r\n });\r\n break;\r\n }\r\n\r\n case '/retention': {\r\n const allObs = await loadObservationsJson(effectiveDataDir) as Array<{\r\n id?: number;\r\n title?: string;\r\n type?: string;\r\n importance?: number;\r\n accessCount?: number;\r\n lastAccessedAt?: string;\r\n createdAt?: string;\r\n entityName?: string;\r\n projectId?: string;\r\n }>;\r\n const observations = filterByProject(allObs, effectiveProjectId);\r\n\r\n const now = Date.now();\r\n const scored = observations.map((obs) => {\r\n const age = now - new Date(obs.createdAt || now).getTime();\r\n const ageHours = age / (1000 * 60 * 60);\r\n const importance = obs.importance ?? 5;\r\n const accessCount = obs.accessCount ?? 0;\r\n\r\n // Exponential decay: score = importance * e^(-λt) + access_bonus\r\n const lambda = 0.01;\r\n const decayScore = importance * Math.exp(-lambda * ageHours);\r\n const accessBonus = Math.min(accessCount * 0.5, 3);\r\n const score = Math.min(decayScore + accessBonus, 10);\r\n\r\n // Immune if importance >= 8 or type is 'gotcha' or 'decision'\r\n const isImmune = importance >= 8 || obs.type === 'gotcha' || obs.type === 'decision';\r\n\r\n return {\r\n id: obs.id,\r\n title: obs.title,\r\n type: obs.type,\r\n entityName: obs.entityName,\r\n score: Math.round(score * 100) / 100,\r\n isImmune,\r\n ageHours: Math.round(ageHours * 10) / 10,\r\n accessCount,\r\n };\r\n });\r\n\r\n // Sort by score descending\r\n scored.sort((a, b) => b.score - a.score);\r\n\r\n const activeCount = scored.filter((s) => s.score >= 3).length;\r\n const staleCount = scored.filter((s) => s.score < 3 && s.score >= 1).length;\r\n const archiveCount = scored.filter((s) => s.score < 1).length;\r\n const immuneCount = scored.filter((s) => s.isImmune).length;\r\n\r\n sendJson(res, {\r\n summary: { active: activeCount, stale: staleCount, archive: archiveCount, immune: immuneCount },\r\n items: scored,\r\n });\r\n break;\r\n }\r\n\r\n default: {\r\n // Handle dynamic routes\r\n const deleteMatch = apiPath.match(/^\\/observations\\/(\\d+)$/);\r\n if (deleteMatch && req.method === 'DELETE') {\r\n const obsId = parseInt(deleteMatch[1], 10);\r\n await withFileLock(effectiveDataDir, async () => {\r\n const allObs = await loadObservationsJson(effectiveDataDir) as Array<{ id?: number;[k: string]: unknown }>;\r\n const idx = allObs.findIndex(o => o.id === obsId);\r\n if (idx === -1) {\r\n sendError(res, 'Observation not found', 404);\r\n } else {\r\n allObs.splice(idx, 1);\r\n await saveObservationsJson(effectiveDataDir, allObs);\r\n\r\n // Sync: clean up graph entity references for this observation\r\n try {\r\n const graph = await loadGraphJsonl(effectiveDataDir);\r\n const prefix = `[#${obsId}] `;\r\n let graphChanged = false;\r\n for (const entity of graph.entities) {\r\n const before = entity.observations.length;\r\n entity.observations = entity.observations.filter(o => !o.startsWith(prefix));\r\n if (entity.observations.length < before) graphChanged = true;\r\n }\r\n if (graphChanged) {\r\n await saveGraphJsonl(effectiveDataDir, graph.entities, graph.relations);\r\n }\r\n } catch { /* graph sync is best-effort */ }\r\n\r\n sendJson(res, { ok: true, deleted: obsId });\r\n }\r\n });\r\n break;\r\n }\r\n\r\n if (apiPath === '/export') {\r\n const graph = await loadGraphJsonl(effectiveDataDir);\r\n const allObs = await loadObservationsJson(effectiveDataDir);\r\n const observations = filterByProject(allObs as Array<{ projectId?: string }>, effectiveProjectId);\r\n const nextId = await loadIdCounter(effectiveDataDir);\r\n const exportData = {\r\n project: { id: effectiveProjectId, name: effectiveProjectName },\r\n exportedAt: new Date().toISOString(),\r\n graph,\r\n observations,\r\n nextId,\r\n };\r\n res.writeHead(200, {\r\n 'Content-Type': 'application/json',\r\n 'Content-Disposition': `attachment; filename=\"memorix-${effectiveProjectId.replace(/\\//g, '-')}-export.json\"`,\r\n });\r\n res.end(JSON.stringify(exportData, null, 2));\r\n break;\r\n }\r\n\r\n sendError(res, 'Not found', 404);\r\n }\r\n }\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Unknown error';\r\n sendError(res, message);\r\n }\r\n}\r\n\r\n/**\r\n * Serve static files from the dashboard/static directory\r\n */\r\nasync function serveStatic(req: IncomingMessage, res: ServerResponse, staticDir: string) {\r\n let urlPath = new URL(req.url || '/', `http://${req.headers.host}`).pathname;\r\n\r\n // SPA: serve index.html for all non-file routes\r\n if (urlPath === '/' || !urlPath.includes('.')) {\r\n urlPath = '/index.html';\r\n }\r\n\r\n const filePath = path.join(staticDir, urlPath);\r\n\r\n // Security: prevent directory traversal\r\n if (!filePath.startsWith(staticDir)) {\r\n sendError(res, 'Forbidden', 403);\r\n return;\r\n }\r\n\r\n try {\r\n const data = await fs.readFile(filePath);\r\n const ext = path.extname(filePath);\r\n res.writeHead(200, {\r\n 'Content-Type': MIME_TYPES[ext] || 'application/octet-stream',\r\n 'Cache-Control': 'no-cache',\r\n });\r\n res.end(data);\r\n } catch {\r\n // Fallback to index.html for SPA routing\r\n try {\r\n const indexData = await fs.readFile(path.join(staticDir, 'index.html'));\r\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\r\n res.end(indexData);\r\n } catch {\r\n sendError(res, 'Not found', 404);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Start the dashboard server\r\n */\r\n\r\n/** Cross-platform open URL in default browser */\r\nfunction openBrowser(url: string) {\r\n const cmd =\r\n process.platform === 'win32' ? `start \"\" \"${url}\"` :\r\n process.platform === 'darwin' ? `open \"${url}\"` :\r\n `xdg-open \"${url}\"`;\r\n exec(cmd, () => { /* ignore errors */ });\r\n}\r\n\r\n/** Mutable dashboard state — updated at runtime when project changes */\r\ninterface DashboardState {\r\n projectId: string;\r\n projectName: string;\r\n dataDir: string;\r\n}\r\n\r\n/** Optional team collaboration instances passed from MCP server */\r\nexport interface TeamInstances {\r\n registry: { listAgents: (filter?: any) => any[]; getActiveCount: () => number; getAgent: (id: string) => any };\r\n fileLocks: { listLocks: (agentId?: string) => any[]; cleanExpired: () => void };\r\n taskManager: { list: (filter?: any) => any[]; getAvailable: () => any[] };\r\n messageBus: { getUnreadCount: (agentId: string) => number };\r\n}\r\n\r\n/** Read full POST body as string */\r\nfunction readBody(req: IncomingMessage): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const chunks: Buffer[] = [];\r\n req.on('data', (c: Buffer) => chunks.push(c));\r\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));\r\n req.on('error', reject);\r\n });\r\n}\r\n\r\nexport async function startDashboard(\r\n dataDir: string,\r\n port: number,\r\n staticDir: string,\r\n projectId: string,\r\n projectName: string,\r\n autoOpen = true,\r\n teamInstances?: TeamInstances,\r\n): Promise<void> {\r\n const resolvedStaticDir = staticDir;\r\n // Derive baseDir from dataDir (parent directory of project-specific dir)\r\n const baseDir = getBaseDataDir();\r\n\r\n // Mutable state — can be updated via /api/set-current-project\r\n const state: DashboardState = { projectId, projectName, dataDir };\r\n\r\n const server = createServer(async (req, res) => {\r\n const url = req.url || '/';\r\n\r\n // POST /api/set-current-project — update the dashboard's current project\r\n // In flat storage, switching project only changes the projectId filter, not the data dir\r\n if (url.startsWith('/api/set-current-project') && req.method === 'POST') {\r\n try {\r\n const body = JSON.parse(await readBody(req));\r\n if (body.projectId) {\r\n state.projectId = body.projectId;\r\n state.projectName = body.projectName || body.projectId.split('/').pop() || body.projectId;\r\n state.dataDir = baseDir; // flat storage: always use base dir\r\n console.error(`[dashboard] Switched current project to: ${state.projectId}`);\r\n sendJson(res, { ok: true, projectId: state.projectId, projectName: state.projectName });\r\n } else {\r\n sendError(res, 'Missing projectId in body', 400);\r\n }\r\n } catch {\r\n sendError(res, 'Invalid JSON body', 400);\r\n }\r\n return;\r\n }\r\n\r\n if (url.startsWith('/api/team') && teamInstances) {\r\n try {\r\n teamInstances.fileLocks.cleanExpired();\r\n const agents = teamInstances.registry.listAgents();\r\n const locks = teamInstances.fileLocks.listLocks();\r\n const tasks = teamInstances.taskManager.list();\r\n const available = teamInstances.taskManager.getAvailable();\r\n sendJson(res, {\r\n agents: agents.map((a: any) => ({\r\n ...a,\r\n unread: teamInstances!.messageBus.getUnreadCount(a.id),\r\n })),\r\n activeCount: teamInstances.registry.getActiveCount(),\r\n locks,\r\n tasks,\r\n availableTasks: available.length,\r\n });\r\n } catch {\r\n sendJson(res, { agents: [], activeCount: 0, locks: [], tasks: [], availableTasks: 0 });\r\n }\r\n return;\r\n }\r\n\r\n if (url.startsWith('/api/')) {\r\n await handleApi(req, res, state.dataDir, state.projectId, state.projectName, baseDir);\r\n } else {\r\n await serveStatic(req, res, resolvedStaticDir);\r\n }\r\n });\r\n\r\n return new Promise((resolve, reject) => {\r\n server.on('error', (err: NodeJS.ErrnoException) => {\r\n if (err.code === 'EADDRINUSE') {\r\n console.error(`Port ${port} is already in use. Try: memorix dashboard --port ${port + 1}`);\r\n reject(err);\r\n } else {\r\n reject(err);\r\n }\r\n });\r\n\r\n server.listen(port, () => {\r\n const url = `http://localhost:${port}`;\r\n console.error(`\\n Memorix Dashboard`);\r\n console.error(` ───────────────────────`);\r\n console.error(` Project: ${projectName} (${projectId})`);\r\n console.error(` Local: ${url}`);\r\n console.error(` Data dir: ${dataDir}`);\r\n console.error(`\\n Press Ctrl+C to stop\\n`);\r\n\r\n // Auto-open browser\r\n if (autoOpen) openBrowser(url);\r\n\r\n resolve();\r\n });\r\n });\r\n}\r\n","/**\n * Agent Registry — Tracks agents in a multi-agent team\n *\n * In-memory registry shared across all MCP sessions on the same HTTP server.\n * Each agent joins with a name, optional role, and capabilities.\n * Registry supports heartbeat for liveness detection.\n */\n\nimport { randomUUID } from 'node:crypto';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface AgentJoinInput {\n name: string;\n role?: string;\n capabilities?: string[];\n}\n\nexport interface AgentInfo {\n id: string;\n name: string;\n role?: string;\n capabilities: string[];\n status: 'active' | 'inactive';\n joinedAt: Date;\n lastSeenAt: Date;\n leftAt?: Date;\n}\n\nexport interface AgentListFilter {\n status?: 'active' | 'inactive';\n}\n\n// ─── Registry ────────────────────────────────────────────────────────\n\nexport class AgentRegistry {\n private agents = new Map<string, AgentInfo>();\n private nameIndex = new Map<string, string>(); // name → id\n\n /**\n * Register an agent. If an agent with the same name already exists,\n * reactivate it with updated info instead of creating a duplicate.\n */\n join(input: AgentJoinInput): AgentInfo {\n const existing = this.nameIndex.get(input.name);\n if (existing) {\n const agent = this.agents.get(existing)!;\n agent.role = input.role;\n agent.capabilities = input.capabilities ?? agent.capabilities;\n agent.status = 'active';\n agent.lastSeenAt = new Date();\n delete agent.leftAt;\n return { ...agent };\n }\n\n const id = randomUUID();\n const now = new Date();\n const agent: AgentInfo = {\n id,\n name: input.name,\n role: input.role,\n capabilities: input.capabilities ?? [],\n status: 'active',\n joinedAt: now,\n lastSeenAt: now,\n };\n\n this.agents.set(id, agent);\n this.nameIndex.set(input.name, id);\n return { ...agent };\n }\n\n /**\n * Mark an agent as inactive. Returns false if agent not found.\n */\n leave(agentId: string): boolean {\n const agent = this.agents.get(agentId);\n if (!agent) return false;\n\n agent.status = 'inactive';\n agent.leftAt = new Date();\n return true;\n }\n\n /**\n * Get info for a specific agent. Returns null if not found.\n */\n getAgent(agentId: string): AgentInfo | null {\n const agent = this.agents.get(agentId);\n return agent ? { ...agent } : null;\n }\n\n /**\n * List agents, optionally filtered by status.\n */\n listAgents(filter?: AgentListFilter): AgentInfo[] {\n const all = [...this.agents.values()];\n if (filter?.status) {\n return all.filter(a => a.status === filter.status).map(a => ({ ...a }));\n }\n return all.map(a => ({ ...a }));\n }\n\n /**\n * Update lastSeenAt for an agent. Returns false if not found.\n */\n heartbeat(agentId: string): boolean {\n const agent = this.agents.get(agentId);\n if (!agent) return false;\n agent.lastSeenAt = new Date();\n return true;\n }\n\n /**\n * Count of currently active agents.\n */\n getActiveCount(): number {\n let count = 0;\n for (const agent of this.agents.values()) {\n if (agent.status === 'active') count++;\n }\n return count;\n }\n\n /** Serialize state for file persistence */\n serialize(): { agents: Record<string, unknown>; nameIndex: Record<string, string> } {\n const agents: Record<string, unknown> = {};\n for (const [id, a] of this.agents) {\n agents[id] = {\n ...a,\n joinedAt: a.joinedAt.toISOString(),\n lastSeenAt: a.lastSeenAt.toISOString(),\n leftAt: a.leftAt?.toISOString() ?? null,\n };\n }\n return { agents, nameIndex: Object.fromEntries(this.nameIndex) };\n }\n\n /** Hydrate state from file persistence */\n hydrate(data: { agents?: Record<string, any>; nameIndex?: Record<string, string> }): void {\n this.agents.clear();\n this.nameIndex.clear();\n if (!data?.agents) return;\n for (const [id, raw] of Object.entries(data.agents)) {\n this.agents.set(id, {\n ...raw,\n joinedAt: new Date(raw.joinedAt),\n lastSeenAt: new Date(raw.lastSeenAt),\n leftAt: raw.leftAt ? new Date(raw.leftAt) : undefined,\n });\n }\n if (data.nameIndex) {\n for (const [name, id] of Object.entries(data.nameIndex)) {\n this.nameIndex.set(name, id);\n }\n }\n }\n}\n","/**\n * Message Bus — Agent-to-agent communication\n *\n * In-memory message queue for team coordination.\n * Messages are temporary (not persisted as observations).\n * Supports direct send, broadcast, inbox retrieval, and read tracking.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { AgentRegistry } from './registry.js';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport type MessageType = 'request' | 'response' | 'info' | 'announcement' | 'contract' | 'error';\n\nexport interface MessageSendInput {\n from: string;\n to: string;\n type: MessageType;\n content: string;\n}\n\nexport interface MessageBroadcastInput {\n from: string;\n type: MessageType;\n content: string;\n}\n\nexport interface Message {\n id: string;\n from: string;\n to: string;\n type: MessageType;\n content: string;\n timestamp: Date;\n read: boolean;\n}\n\n// ─── Message Bus ─────────────────────────────────────────────────────\n\n/** Max messages per inbox. Oldest read messages are evicted first. */\nconst MAX_INBOX_SIZE = 200;\n/** Max message content length in bytes */\nconst MAX_CONTENT_LENGTH = 10_000;\n\nexport class MessageBus {\n private inboxes = new Map<string, Message[]>();\n private registry: AgentRegistry;\n\n constructor(registry: AgentRegistry) {\n this.registry = registry;\n }\n\n /**\n * Send a message to a specific agent.\n * Throws if receiver is unknown.\n */\n send(input: MessageSendInput): Message {\n const receiver = this.registry.getAgent(input.to);\n if (!receiver) {\n throw new Error(`Unknown receiver agent: ${input.to}`);\n }\n if (receiver.status !== 'active') {\n throw new Error(`Receiver agent is inactive: ${receiver.name}`);\n }\n\n const msg: Message = {\n id: randomUUID(),\n from: input.from,\n to: input.to,\n type: input.type,\n content: input.content,\n timestamp: new Date(),\n read: false,\n };\n\n const inbox = this.inboxes.get(input.to) ?? [];\n inbox.push(msg);\n\n // Evict oldest read messages if inbox exceeds limit\n if (inbox.length > MAX_INBOX_SIZE) {\n const readIndices: number[] = [];\n for (let i = 0; i < inbox.length; i++) {\n if (inbox[i].read) readIndices.push(i);\n }\n // Remove oldest read messages first\n const toRemove = inbox.length - MAX_INBOX_SIZE;\n for (let i = Math.min(toRemove, readIndices.length) - 1; i >= 0; i--) {\n inbox.splice(readIndices[i], 1);\n }\n // If still over limit, remove oldest unread\n while (inbox.length > MAX_INBOX_SIZE) {\n inbox.shift();\n }\n }\n\n this.inboxes.set(input.to, inbox);\n return msg;\n }\n\n /**\n * Broadcast a message to all active agents except the sender.\n */\n broadcast(input: MessageBroadcastInput): Message[] {\n const activeAgents = this.registry.listAgents({ status: 'active' });\n const messages: Message[] = [];\n\n for (const agent of activeAgents) {\n if (agent.id === input.from) continue;\n\n const msg = this.send({\n from: input.from,\n to: agent.id,\n type: input.type,\n content: input.content,\n });\n messages.push(msg);\n }\n\n return messages;\n }\n\n /**\n * Get all messages in an agent's inbox (both read and unread).\n */\n getInbox(agentId: string): Message[] {\n return [...(this.inboxes.get(agentId) ?? [])];\n }\n\n /**\n * Mark specific messages as read.\n */\n markRead(agentId: string, messageIds: string[]): number {\n const inbox = this.inboxes.get(agentId);\n if (!inbox) return 0;\n\n const idSet = new Set(messageIds);\n let count = 0;\n for (const msg of inbox) {\n if (idSet.has(msg.id) && !msg.read) {\n msg.read = true;\n count++;\n }\n }\n return count;\n }\n\n /**\n * Count unread messages for an agent.\n */\n getUnreadCount(agentId: string): number {\n const inbox = this.inboxes.get(agentId);\n if (!inbox) return 0;\n return inbox.filter(m => !m.read).length;\n }\n\n /**\n * Remove all read messages from an agent's inbox.\n * Returns the number of messages pruned.\n */\n pruneRead(agentId: string): number {\n const inbox = this.inboxes.get(agentId);\n if (!inbox) return 0;\n const before = inbox.length;\n const unread = inbox.filter(m => !m.read);\n this.inboxes.set(agentId, unread);\n return before - unread.length;\n }\n\n /**\n * Clear all messages for an agent (used on agent leave).\n */\n clearInbox(agentId: string): void {\n this.inboxes.delete(agentId);\n }\n\n /** Max allowed content length */\n static get MAX_CONTENT_LENGTH() { return MAX_CONTENT_LENGTH; }\n\n /** Serialize state for file persistence */\n serialize(): { inboxes: Record<string, unknown[]> } {\n const inboxes: Record<string, unknown[]> = {};\n for (const [agentId, msgs] of this.inboxes) {\n inboxes[agentId] = msgs.map(m => ({\n ...m,\n timestamp: m.timestamp.toISOString(),\n }));\n }\n return { inboxes };\n }\n\n /** Hydrate state from file persistence */\n hydrate(data: { inboxes?: Record<string, any[]> }): void {\n this.inboxes.clear();\n if (!data?.inboxes) return;\n for (const [agentId, msgs] of Object.entries(data.inboxes)) {\n this.inboxes.set(agentId, msgs.map(m => ({\n ...m,\n timestamp: new Date(m.timestamp),\n })));\n }\n }\n}\n","/**\n * File Lock Registry — Advisory file locks for multi-agent coordination\n *\n * Prevents conflicting edits when multiple agents work on the same project.\n * Locks are advisory (not enforced at OS level) with TTL auto-release.\n * Default TTL: 10 minutes. Agents see lock status via session_start injection.\n */\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface LockResult {\n success: boolean;\n lockedBy: string;\n file: string;\n}\n\nexport interface LockInfo {\n file: string;\n lockedBy: string;\n lockedAt: Date;\n expiresAt: Date;\n}\n\nexport interface LockOptions {\n ttlMs?: number;\n}\n\nconst DEFAULT_TTL_MS = 10 * 60 * 1000; // 10 minutes\n\n// ─── Internal Lock Entry ─────────────────────────────────────────────\n\ninterface LockEntry {\n file: string;\n lockedBy: string;\n lockedAt: Date;\n expiresAt: Date;\n}\n\n// ─── Registry ────────────────────────────────────────────────────────\n\nexport class FileLockRegistry {\n private locks = new Map<string, LockEntry>();\n\n /**\n * Attempt to lock a file for an agent.\n * Returns success:true if lock acquired, or success:false with current owner.\n * Same agent re-locking is idempotent (refreshes TTL).\n */\n lock(file: string, agentId: string, options?: LockOptions): LockResult {\n const ttl = options?.ttlMs ?? DEFAULT_TTL_MS;\n\n // Clean expired locks first\n this.cleanExpiredEntry(file);\n\n const existing = this.locks.get(file);\n\n if (existing) {\n if (existing.lockedBy === agentId) {\n // Same agent — refresh TTL\n existing.expiresAt = new Date(Date.now() + ttl);\n return { success: true, lockedBy: agentId, file };\n }\n // Different agent holds the lock\n return { success: false, lockedBy: existing.lockedBy, file };\n }\n\n // No lock — acquire\n const now = new Date();\n this.locks.set(file, {\n file,\n lockedBy: agentId,\n lockedAt: now,\n expiresAt: new Date(now.getTime() + ttl),\n });\n\n return { success: true, lockedBy: agentId, file };\n }\n\n /**\n * Release a lock. Only the owner can release.\n * Returns true if released, false if not found or not owner.\n */\n unlock(file: string, agentId: string): boolean {\n const entry = this.locks.get(file);\n if (!entry) return false;\n if (entry.lockedBy !== agentId) return false;\n\n this.locks.delete(file);\n return true;\n }\n\n /**\n * Get lock status for a specific file. Returns null if unlocked.\n */\n getStatus(file: string): LockInfo | null {\n this.cleanExpiredEntry(file);\n const entry = this.locks.get(file);\n if (!entry) return null;\n return { ...entry };\n }\n\n /**\n * List all active locks, optionally filtered by agent.\n */\n listLocks(agentId?: string): LockInfo[] {\n this.cleanExpired();\n const all = [...this.locks.values()];\n const filtered = agentId ? all.filter(l => l.lockedBy === agentId) : all;\n return filtered.map(l => ({ ...l }));\n }\n\n /**\n * Release all locks held by a specific agent. Returns count released.\n */\n releaseAll(agentId: string): number {\n let count = 0;\n for (const [file, entry] of this.locks) {\n if (entry.lockedBy === agentId) {\n this.locks.delete(file);\n count++;\n }\n }\n return count;\n }\n\n /**\n * Remove all expired locks.\n */\n cleanExpired(): void {\n const now = Date.now();\n for (const [file, entry] of this.locks) {\n if (entry.expiresAt.getTime() <= now) {\n this.locks.delete(file);\n }\n }\n }\n\n /**\n * Check and remove a single expired lock entry.\n */\n private cleanExpiredEntry(file: string): void {\n const entry = this.locks.get(file);\n if (entry && entry.expiresAt.getTime() <= Date.now()) {\n this.locks.delete(file);\n }\n }\n\n /** Serialize state for file persistence */\n serialize(): { locks: Record<string, unknown> } {\n const locks: Record<string, unknown> = {};\n for (const [file, entry] of this.locks) {\n locks[file] = {\n ...entry,\n lockedAt: entry.lockedAt.toISOString(),\n expiresAt: entry.expiresAt.toISOString(),\n };\n }\n return { locks };\n }\n\n /** Hydrate state from file persistence */\n hydrate(data: { locks?: Record<string, any> }): void {\n this.locks.clear();\n if (!data?.locks) return;\n for (const [file, raw] of Object.entries(data.locks)) {\n this.locks.set(file, {\n ...(raw as any),\n lockedAt: new Date((raw as any).lockedAt),\n expiresAt: new Date((raw as any).expiresAt),\n });\n }\n }\n}\n","/**\n * Task Manager — Simple task DAG with dependencies\n *\n * Agents can create tasks, claim them, complete them, and query available work.\n * Dependencies are validated: a task can only be claimed when all deps are completed.\n * Simple JSON format — no complex graph structures.\n */\n\nimport { randomUUID } from 'node:crypto';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed';\n\nexport interface TaskCreateInput {\n description: string;\n deps?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface Task {\n id: string;\n description: string;\n status: TaskStatus;\n deps: string[];\n assignee?: string;\n result?: string;\n metadata?: Record<string, unknown>;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface TaskListFilter {\n status?: TaskStatus;\n assignee?: string;\n}\n\n// ─── Manager ─────────────────────────────────────────────────────────\n\nexport class TaskManager {\n private tasks = new Map<string, Task>();\n\n /**\n * Create a new task. Validates that all dependency IDs exist.\n */\n create(input: TaskCreateInput): Task {\n const deps = input.deps ?? [];\n\n // Validate deps exist\n for (const dep of deps) {\n if (!this.tasks.has(dep)) {\n throw new Error(`Unknown dependency task: ${dep}`);\n }\n }\n\n const now = new Date();\n const task: Task = {\n id: randomUUID(),\n description: input.description,\n status: 'pending',\n deps,\n metadata: input.metadata,\n createdAt: now,\n updatedAt: now,\n };\n\n this.tasks.set(task.id, task);\n return { ...task };\n }\n\n /**\n * Claim a pending task for an agent.\n * Validates: task exists, not claimed by another, all deps completed.\n */\n claim(taskId: string, agentId: string): Task {\n const task = this.tasks.get(taskId);\n if (!task) throw new Error(`Task not found: ${taskId}`);\n\n // Allow same agent to re-claim\n if (task.assignee && task.assignee !== agentId) {\n throw new Error(`Task already claimed by ${task.assignee}`);\n }\n\n // Check all dependencies are completed\n for (const depId of task.deps) {\n const dep = this.tasks.get(depId);\n if (!dep || dep.status !== 'completed') {\n throw new Error(`Cannot claim: dependencies not completed (${depId})`);\n }\n }\n\n task.assignee = agentId;\n task.status = 'in_progress';\n task.updatedAt = new Date();\n return { ...task };\n }\n\n /**\n * Complete a task with a result. Only the assignee can complete,\n * unless allowRescue is true (used when original assignee left).\n */\n complete(taskId: string, agentId: string, result: string, allowRescue = false): Task {\n const task = this.tasks.get(taskId);\n if (!task) throw new Error(`Task not found: ${taskId}`);\n if (!task.assignee) throw new Error(`Task not claimed: ${taskId}`);\n if (task.assignee !== agentId && !allowRescue) {\n throw new Error(`Only assignee ${task.assignee} can complete this task`);\n }\n\n task.assignee = agentId;\n task.status = 'completed';\n task.result = result;\n task.updatedAt = new Date();\n return { ...task };\n }\n\n /**\n * Release all in_progress tasks assigned to a specific agent.\n * Returns them to 'pending' so other agents can claim them.\n */\n releaseByAgent(agentId: string): number {\n let count = 0;\n for (const task of this.tasks.values()) {\n if (task.assignee === agentId && task.status === 'in_progress') {\n task.status = 'pending';\n task.assignee = undefined;\n task.updatedAt = new Date();\n count++;\n }\n }\n return count;\n }\n\n /**\n * List tasks with optional filters.\n */\n list(filter?: TaskListFilter): Task[] {\n let all = [...this.tasks.values()];\n if (filter?.status) {\n all = all.filter(t => t.status === filter.status);\n }\n if (filter?.assignee) {\n all = all.filter(t => t.assignee === filter.assignee);\n }\n return all.map(t => ({ ...t }));\n }\n\n /**\n * Get tasks that are available to be claimed:\n * - status is 'pending'\n * - all dependencies are 'completed'\n */\n getAvailable(): Task[] {\n const result: Task[] = [];\n for (const task of this.tasks.values()) {\n if (task.status !== 'pending') continue;\n\n const depsReady = task.deps.every(depId => {\n const dep = this.tasks.get(depId);\n return dep && dep.status === 'completed';\n });\n\n if (depsReady) {\n result.push({ ...task });\n }\n }\n return result;\n }\n\n /**\n * Get a single task by ID.\n */\n getTask(taskId: string): Task | null {\n const task = this.tasks.get(taskId);\n return task ? { ...task } : null;\n }\n\n /**\n * Check if a task's assignee matches the given agentId.\n */\n isAssignee(taskId: string, agentId: string): boolean {\n const task = this.tasks.get(taskId);\n return task?.assignee === agentId;\n }\n\n /** Serialize state for file persistence */\n serialize(): { tasks: Record<string, unknown> } {\n const tasks: Record<string, unknown> = {};\n for (const [id, t] of this.tasks) {\n tasks[id] = {\n ...t,\n createdAt: t.createdAt.toISOString(),\n updatedAt: t.updatedAt.toISOString(),\n };\n }\n return { tasks };\n }\n\n /** Hydrate state from file persistence */\n hydrate(data: { tasks?: Record<string, any> }): void {\n this.tasks.clear();\n if (!data?.tasks) return;\n for (const [id, raw] of Object.entries(data.tasks)) {\n this.tasks.set(id, {\n ...(raw as any),\n createdAt: new Date((raw as any).createdAt),\n updatedAt: new Date((raw as any).updatedAt),\n });\n }\n }\n}\n","/**\n * Team State Persistence — File-based shared state for cross-IDE team collaboration\n *\n * In stdio mode, each IDE spawns its own MCP process with isolated in-memory team state.\n * This persistence layer writes team state to a shared JSON file so all MCP processes\n * (Windsurf, Cursor, Claude Code, Antigravity, etc.) see the same agents, messages,\n * locks, and tasks.\n *\n * sync() — reload from disk if file changed (mtime check)\n * flush() — atomic write to disk (write tmp + rename)\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { statSync, renameSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { AgentRegistry } from './registry.js';\nimport type { MessageBus } from './messages.js';\nimport type { TaskManager } from './tasks.js';\nimport type { FileLockRegistry } from './file-locks.js';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\ninterface TeamStateSnapshot {\n version: 1;\n updatedAt: string;\n registry: ReturnType<AgentRegistry['serialize']>;\n messages: ReturnType<MessageBus['serialize']>;\n tasks: ReturnType<TaskManager['serialize']>;\n locks: ReturnType<FileLockRegistry['serialize']>;\n}\n\n// ─── Persistence ─────────────────────────────────────────────────────\n\nexport class TeamPersistence {\n private lastMtimeMs = 0;\n\n constructor(\n private filePath: string,\n private registry: AgentRegistry,\n private messageBus: MessageBus,\n private taskManager: TaskManager,\n private fileLocks: FileLockRegistry,\n ) {}\n\n /** Reload state from disk if the file changed since last read */\n async sync(): Promise<void> {\n try {\n if (!existsSync(this.filePath)) return;\n const st = statSync(this.filePath);\n if (st.mtimeMs <= this.lastMtimeMs) return;\n } catch {\n return;\n }\n\n try {\n const raw = await readFile(this.filePath, 'utf8');\n const snap: TeamStateSnapshot = JSON.parse(raw);\n if (snap.version !== 1) return;\n\n this.registry.hydrate(snap.registry);\n this.messageBus.hydrate(snap.messages);\n this.taskManager.hydrate(snap.tasks);\n this.fileLocks.hydrate(snap.locks);\n\n try { this.lastMtimeMs = statSync(this.filePath).mtimeMs; } catch { /* */ }\n } catch {\n // Corrupted or partial write — ignore, will be overwritten on next flush\n }\n }\n\n /** Write current state to disk atomically (tmp + rename) */\n async flush(): Promise<void> {\n const snap: TeamStateSnapshot = {\n version: 1,\n updatedAt: new Date().toISOString(),\n registry: this.registry.serialize(),\n messages: this.messageBus.serialize(),\n tasks: this.taskManager.serialize(),\n locks: this.fileLocks.serialize(),\n };\n\n await mkdir(dirname(this.filePath), { recursive: true });\n const tmp = this.filePath + '.' + process.pid + '.tmp';\n await writeFile(tmp, JSON.stringify(snap, null, 2), 'utf8');\n\n try {\n renameSync(tmp, this.filePath);\n } catch {\n // Fallback: direct write if rename fails (cross-device)\n await writeFile(this.filePath, JSON.stringify(snap, null, 2), 'utf8');\n try { const { unlinkSync } = await import('node:fs'); unlinkSync(tmp); } catch { /* */ }\n }\n\n try { this.lastMtimeMs = statSync(this.filePath).mtimeMs; } catch { /* */ }\n }\n}\n","/**\n * Hook Installers\n *\n * Auto-detect installed agents and generate hook configurations.\n * Each agent has a different config format but the hook command is the same:\n * memorix hook\n *\n * The hook handler reads stdin JSON from the agent, normalizes it, and auto-stores.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\n\nimport type { AgentName, AgentHookConfig } from '../types.js';\n\n/**\n * Resolve the hook command for the current platform.\n * On Windows, bare 'memorix' may resolve to a .ps1 script that non-PowerShell\n * environments can't execute. Using 'memorix.cmd' explicitly targets the CMD\n * shim that npm creates, which works in all shell environments and properly\n * forwards stdin (unlike 'cmd /c memorix' which can break stdin piping).\n */\nfunction resolveHookCommand(): string {\n if (process.platform === 'win32') {\n return 'memorix.cmd';\n }\n return 'memorix';\n}\n\n/**\n * Generate Claude Code hook config.\n * Format: .claude/settings.json\n * See: https://docs.anthropic.com/en/docs/claude-code/hooks\n */\nfunction generateClaudeConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n const hookEntry = {\n type: 'command',\n command: cmd,\n timeout: 10,\n };\n\n return {\n hooks: {\n SessionStart: [{ hooks: [hookEntry] }],\n PostToolUse: [{ hooks: [hookEntry] }],\n UserPromptSubmit: [{ hooks: [hookEntry] }],\n PreCompact: [{ hooks: [hookEntry] }],\n Stop: [{ hooks: [hookEntry] }],\n },\n };\n}\n\n/**\n * Generate GitHub Copilot hook config.\n * Format: .github/hooks/memorix.json — version:1 + bash/powershell fields\n * See: https://docs.github.com/en/copilot/reference/hooks-configuration\n */\nfunction generateCopilotConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n const hookEntry = {\n type: 'command',\n bash: cmd,\n powershell: cmd,\n timeoutSec: 10,\n };\n\n return {\n version: 1,\n hooks: {\n sessionStart: [hookEntry],\n sessionEnd: [hookEntry],\n userPromptSubmitted: [hookEntry],\n // NOTE: preToolUse intentionally omitted — VS Code Copilot requires\n // hookSpecificOutput.permissionDecision in the response; memorix is\n // an observer, not a gatekeeper, so we only use postToolUse.\n postToolUse: [hookEntry],\n errorOccurred: [hookEntry],\n },\n };\n}\n\n/**\n * Generate Gemini CLI / Antigravity hook config.\n * Format: .gemini/settings.json — PascalCase events, timeout in milliseconds\n * See: https://geminicli.com/docs/hooks/\n */\nfunction generateGeminiConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n\n // Gemini CLI hooks: defined in settings.json under \"hooks\" object.\n // Each event key (SessionStart, AfterTool, etc.) maps to an array of hook definitions.\n // No \"enabled\" flag needed — hooks are active simply by being defined.\n // See: https://geminicli.com/docs/hooks/reference/\n function entry(name: string, desc: string) {\n return {\n matcher: '*',\n hooks: [{ name, type: 'command', command: cmd, description: desc }],\n };\n }\n\n return {\n hooks: {\n SessionStart: [entry('memorix-session-start', 'Load memorix context at session start')],\n AfterTool: [entry('memorix-after-tool', 'Record tool usage in memorix')],\n AfterAgent: [entry('memorix-after-agent', 'Record agent response in memorix')],\n PreCompress: [entry('memorix-pre-compress', 'Save context before compression')],\n },\n };\n}\n\n/**\n * Generate Windsurf Cascade hooks config.\n */\nfunction generateWindsurfConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n const hookEntry = {\n command: cmd,\n show_output: false,\n };\n\n return {\n hooks: {\n post_write_code: [hookEntry],\n post_run_command: [hookEntry],\n post_mcp_tool_use: [hookEntry],\n pre_user_prompt: [hookEntry],\n post_cascade_response: [hookEntry],\n },\n };\n}\n\n/**\n * Generate Cursor hooks config.\n */\nfunction generateCursorConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n // Cursor hooks format: version (number) + each event is an array of hook scripts\n // See: https://cursor.com/docs/agent/hooks\n const hookScript = { command: cmd };\n return {\n version: 1,\n hooks: {\n sessionStart: [hookScript],\n beforeSubmitPrompt: [hookScript],\n afterFileEdit: [hookScript],\n beforeShellExecution: [hookScript],\n afterMCPExecution: [hookScript],\n preCompact: [hookScript],\n stop: [hookScript],\n },\n };\n}\n\n/**\n * Generate Kiro hook files.\n * Format: .kiro/hooks/*.kiro.hook — JSON config\n * See: https://kiro.dev/docs/hooks/\n * Schema confirmed from: github.com/awsdataarchitect/kiro-best-practices\n */\nfunction generateKiroHookFiles(): Array<{ filename: string; content: string }> {\n const cmd = `${resolveHookCommand()} hook`;\n return [\n {\n filename: 'memorix-agent-stop.kiro.hook',\n content: JSON.stringify({\n enabled: true,\n name: 'Memorix Session Memory',\n description: 'Record session context when agent completes a turn',\n version: '1',\n when: { type: 'agentStop' },\n then: {\n type: 'askAgent',\n prompt: 'Call memorix MCP tools to store important context from this conversation:\\n1. Use memorix_store to record any decisions, bug fixes, gotchas, or configuration changes\\n2. Include relevant file paths and concepts for searchability',\n },\n }, null, 2),\n },\n {\n filename: 'memorix-prompt-submit.kiro.hook',\n content: JSON.stringify({\n enabled: true,\n name: 'Memorix Context Loader',\n description: 'Load relevant memories when user submits a prompt',\n version: '1',\n when: { type: 'promptSubmit' },\n then: {\n type: 'askAgent',\n prompt: 'Before responding, load context:\\n1. Call memorix_session_start to get previous session summary and key memories\\n2. Call memorix_search with a query related to the user\\'s prompt for additional context\\n3. If search results are found, use memorix_detail to fetch the most relevant ones\\n4. Reference relevant memories naturally in your response',\n },\n }, null, 2),\n },\n {\n filename: 'memorix-file-save.kiro.hook',\n content: JSON.stringify({\n enabled: true,\n name: 'Memorix File Change Tracker',\n description: 'Track significant file changes for cross-session memory',\n version: '1',\n when: {\n type: 'fileEdited',\n patterns: ['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx', '**/*.py', '**/*.rs', '**/*.go', '**/*.java', '**/*.md'],\n },\n then: {\n type: 'runCommand',\n command: cmd,\n },\n }, null, 2),\n },\n ];\n}\n\n/**\n * Generate OpenCode plugin file content.\n * Format: .opencode/plugins/memorix.js — Bun-compatible JS module\n * See: https://opencode.ai/docs/plugins/\n *\n * The plugin hooks into OpenCode events and pipes JSON to `memorix hook`\n * via Bun.spawn, matching the same stdin/stdout protocol used by all agents.\n */\nfunction generateOpenCodePlugin(): string {\n return `/**\n * Memorix — Cross-Agent Memory Bridge Plugin for OpenCode\n *\n * Automatically captures session context and tool usage,\n * piping events to \\`memorix hook\\` for cross-agent memory persistence.\n *\n * Generated by: memorix installHooks('opencode', projectRoot)\n * Docs: https://github.com/AVIDS2/memorix\n */\nexport const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {\n // Generate a stable session ID for this plugin lifetime\n const sessionId = \\`opencode-\\${Date.now().toString(36)}-\\${Math.random().toString(36).slice(2, 8)}\\`;\n\n /** Pipe event JSON to memorix hook via temp file (Windows .cmd stdin workaround) */\n async function runHook(payload) {\n payload.session_id = sessionId;\n const tmpDir = Bun.env.TEMP || Bun.env.TMP || '/tmp';\n const tmpPath = \\`\\${tmpDir}/memorix-hook-\\${Date.now()}.json\\`;\n try {\n const data = JSON.stringify(payload);\n await Bun.write(tmpPath, data);\n // cat | pipe works through .cmd wrappers; < redirect does NOT\n await $\\`cat \\${tmpPath} | memorix hook\\`.quiet().nothrow();\n } catch {\n // Silent — hooks must never break the agent\n } finally {\n try { const { unlinkSync } = await import('node:fs'); unlinkSync(tmpPath); } catch {}\n }\n }\n\n return {\n /** Catch-all event handler for session lifecycle + file events */\n event: async ({ event }) => {\n if (event.type === 'session.created') {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'session.created',\n cwd: directory,\n });\n } else if (event.type === 'session.idle') {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'session.idle',\n cwd: directory,\n });\n } else if (event.type === 'file.edited') {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'file.edited',\n file_path: event.properties?.path ?? '',\n cwd: directory,\n });\n } else if (event.type === 'command.executed') {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'command.executed',\n command: event.properties?.command ?? '',\n cwd: directory,\n });\n }\n },\n\n /** Record tool usage after execution (hook, not event) */\n 'tool.execute.after': async (input, output) => {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'tool.execute.after',\n tool_name: input.tool,\n tool_input: input.args,\n cwd: directory,\n });\n },\n\n /** Inject memorix context into compaction prompt */\n 'experimental.session.compacting': async (input, output) => {\n output.context.push(\n '## Memorix Cross-Agent Memory\\\\n' +\n 'Before compacting, use memorix_store to save important discoveries, decisions, and gotchas.\\\\n' +\n 'After compacting, use memorix_session_start to reload session context, then memorix_search for specific topics.'\n );\n },\n };\n};\n`;\n}\n\n/**\n * Get the config file path for an agent (project-level).\n */\nfunction getProjectConfigPath(agent: AgentName, projectRoot: string): string {\n switch (agent) {\n case 'claude':\n // Claude Code reads hooks from .claude/settings.local.json (project-level, gitignored)\n return path.join(projectRoot, '.claude', 'settings.local.json');\n case 'copilot':\n return path.join(projectRoot, '.github', 'hooks', 'memorix.json');\n case 'windsurf':\n return path.join(projectRoot, '.windsurf', 'hooks.json');\n case 'cursor':\n return path.join(projectRoot, '.cursor', 'hooks.json');\n case 'kiro':\n return path.join(projectRoot, '.kiro', 'hooks', 'memorix-agent-stop.kiro.hook');\n case 'codex':\n // Codex has no hooks system — only rules (AGENTS.md)\n return path.join(projectRoot, 'AGENTS.md');\n case 'trae':\n // Trae has no hooks system — only rules (.trae/rules/project_rules.md)\n return path.join(projectRoot, '.trae', 'rules', 'project_rules.md');\n case 'opencode':\n // OpenCode uses plugin files for hooks\n return path.join(projectRoot, '.opencode', 'plugins', 'memorix.js');\n case 'antigravity':\n return path.join(projectRoot, '.gemini', 'settings.json');\n default:\n return path.join(projectRoot, '.memorix', 'hooks.json');\n }\n}\n\n/**\n * Get the global config file path for an agent.\n */\nfunction getGlobalConfigPath(agent: AgentName): string {\n const home = os.homedir();\n switch (agent) {\n case 'claude':\n case 'copilot':\n return path.join(home, '.claude', 'settings.json');\n case 'windsurf':\n return path.join(home, '.codeium', 'windsurf', 'hooks.json');\n case 'cursor':\n return path.join(home, '.cursor', 'hooks.json');\n case 'antigravity':\n return path.join(home, '.gemini', 'settings.json');\n case 'opencode':\n return path.join(home, '.config', 'opencode', 'plugins', 'memorix.js');\n case 'trae':\n return path.join(home, '.trae', 'rules', 'project_rules.md');\n default:\n return path.join(home, '.memorix', 'hooks.json');\n }\n}\n\n/**\n * Detect which agents are installed on the system.\n */\nexport async function detectInstalledAgents(): Promise<AgentName[]> {\n const agents: AgentName[] = [];\n const home = os.homedir();\n\n // Check for Claude Code\n const claudeDir = path.join(home, '.claude');\n try {\n await fs.access(claudeDir);\n agents.push('claude');\n } catch { /* not installed */ }\n\n // Check for Windsurf\n const windsurfDir = path.join(home, '.codeium', 'windsurf');\n try {\n await fs.access(windsurfDir);\n agents.push('windsurf');\n } catch { /* not installed */ }\n\n // Check for Cursor\n const cursorDir = path.join(home, '.cursor');\n try {\n await fs.access(cursorDir);\n agents.push('cursor');\n } catch { /* not installed */ }\n\n // Check for VS Code Copilot (independent of Claude Code — different hook paths)\n const vscodeDir = path.join(home, '.vscode');\n try {\n await fs.access(vscodeDir);\n agents.push('copilot');\n } catch { /* not installed */ }\n\n // Check for Kiro\n const kiroConfig = path.join(home, '.kiro');\n try {\n await fs.access(kiroConfig);\n agents.push('kiro');\n } catch { /* not installed */ }\n\n // Check for Codex\n const codexDir = path.join(home, '.codex');\n try {\n await fs.access(codexDir);\n agents.push('codex');\n } catch { /* not installed */ }\n\n // Check for Antigravity / Gemini CLI (both share ~/.gemini/)\n const geminiDir = path.join(home, '.gemini');\n try {\n await fs.access(geminiDir);\n agents.push('antigravity');\n } catch { /* not installed */ }\n\n // Check for OpenCode\n const opencodeDir = path.join(home, '.config', 'opencode');\n try {\n await fs.access(opencodeDir);\n agents.push('opencode');\n } catch { /* not installed */ }\n\n // Check for Trae\n const traeDir = path.join(home, '.trae');\n try {\n await fs.access(traeDir);\n agents.push('trae');\n } catch { /* not installed */ }\n\n return agents;\n}\n\n/**\n * Install hooks for a specific agent.\n */\nexport async function installHooks(\n agent: AgentName,\n projectRoot: string,\n global = false,\n): Promise<AgentHookConfig> {\n const configPath = global\n ? getGlobalConfigPath(agent)\n : getProjectConfigPath(agent, projectRoot);\n\n let generated: Record<string, unknown> | string;\n\n switch (agent) {\n case 'claude':\n generated = generateClaudeConfig();\n break;\n case 'copilot':\n generated = generateCopilotConfig();\n break;\n case 'windsurf':\n generated = generateWindsurfConfig();\n break;\n case 'cursor':\n generated = generateCursorConfig();\n break;\n case 'antigravity':\n generated = generateGeminiConfig();\n break;\n case 'kiro':\n generated = 'kiro-multi'; // handled separately below\n break;\n case 'codex':\n // Codex has no hooks — only install rules\n await installAgentRules(agent, projectRoot);\n return {\n agent,\n configPath: getProjectConfigPath(agent, projectRoot),\n events: [],\n generated: { note: 'Codex has no hooks system, only rules (AGENTS.md) installed' },\n };\n case 'trae':\n // Trae has no hooks system — only install rules\n await installAgentRules(agent, projectRoot);\n return {\n agent,\n configPath: getProjectConfigPath(agent, projectRoot),\n events: [],\n generated: { note: 'Trae has no hooks system, only rules (.trae/rules/project_rules.md) installed' },\n };\n case 'opencode': {\n // OpenCode uses JS plugin files for hooks\n const pluginContent = generateOpenCodePlugin();\n const pluginPath = global\n ? getGlobalConfigPath(agent)\n : getProjectConfigPath(agent, projectRoot);\n await fs.mkdir(path.dirname(pluginPath), { recursive: true });\n await fs.writeFile(pluginPath, pluginContent, 'utf-8');\n await installAgentRules(agent, projectRoot);\n return {\n agent,\n configPath: pluginPath,\n events: ['session_start', 'session_end', 'post_tool', 'post_edit', 'pre_compact'],\n generated: { note: 'OpenCode plugin installed at ' + pluginPath },\n };\n }\n default:\n generated = generateClaudeConfig(); // fallback\n }\n\n // Ensure directory exists\n await fs.mkdir(path.dirname(configPath), { recursive: true });\n\n if (agent === 'kiro') {\n // Kiro uses multiple .kiro.hook files\n const hookFiles = generateKiroHookFiles();\n const hooksDir = path.join(path.dirname(configPath));\n await fs.mkdir(hooksDir, { recursive: true });\n for (const hf of hookFiles) {\n await fs.writeFile(path.join(hooksDir, hf.filename), hf.content, 'utf-8');\n }\n } else {\n // JSON-based configs: merge with existing if present\n let existing: Record<string, unknown> = {};\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n existing = JSON.parse(content);\n } catch { /* file doesn't exist yet */ }\n\n // Deep-merge generated keys so we don't overwrite user's existing config\n const gen = generated as Record<string, unknown>;\n const merged = { ...existing };\n\n // CRITICAL: version must be a number (Cursor requires this)\n // Always use generated version to fix corrupted configs\n if (typeof gen.version === 'number') {\n merged.version = gen.version;\n } else if (typeof merged.version !== 'number') {\n // Fallback: ensure version is always a number\n merged.version = 1;\n }\n\n // Merge 'hooks' key (all agents)\n if (gen.hooks && typeof gen.hooks === 'object') {\n const existingHooks = (existing.hooks && typeof existing.hooks === 'object')\n ? existing.hooks as Record<string, unknown>\n : {};\n merged.hooks = { ...existingHooks, ...(gen.hooks as Record<string, unknown>) };\n }\n\n // Merge 'tools' key (preserve any user-defined tools config)\n if (gen.tools && typeof gen.tools === 'object') {\n const existingTools = (existing.tools && typeof existing.tools === 'object')\n ? existing.tools as Record<string, unknown>\n : {};\n merged.tools = { ...existingTools, ...(gen.tools as Record<string, unknown>) };\n }\n\n // Clean up stale keys from older memorix versions\n if (agent === 'antigravity') {\n const h = merged.hooks as Record<string, unknown> | undefined;\n if (h && typeof h.enabled === 'boolean') delete h.enabled;\n const t = merged.tools as Record<string, unknown> | undefined;\n if (t) {\n delete t.enableHooks;\n if (Object.keys(t).length === 0) delete merged.tools;\n }\n }\n if (agent === 'copilot') {\n // Remove preToolUse — VS Code Copilot requires hookSpecificOutput\n // in response which memorix doesn't provide (observer, not gatekeeper)\n const h = merged.hooks as Record<string, unknown> | undefined;\n if (h) delete h.preToolUse;\n }\n\n await fs.writeFile(configPath, JSON.stringify(merged, null, 2), 'utf-8');\n }\n\n const events: Array<import('../types.js').HookEvent> = [];\n switch (agent) {\n case 'claude':\n events.push('session_start', 'post_tool', 'user_prompt', 'pre_compact', 'session_end');\n break;\n case 'copilot':\n events.push('session_start', 'session_end', 'user_prompt', 'post_tool');\n break;\n case 'windsurf':\n events.push('post_edit', 'post_command', 'post_tool', 'user_prompt', 'post_response');\n break;\n case 'cursor':\n events.push('session_start', 'user_prompt', 'post_edit', 'post_tool', 'pre_compact', 'session_end');\n break;\n case 'antigravity':\n events.push('session_start', 'post_tool', 'post_response', 'pre_compact');\n break;\n case 'kiro':\n events.push('session_end', 'user_prompt', 'post_edit');\n break;\n }\n\n // Install agent rules alongside hooks\n await installAgentRules(agent, projectRoot);\n\n return {\n agent,\n configPath,\n events,\n generated: typeof generated === 'string' ? { content: generated } : generated,\n };\n}\n\n/**\n * Install memorix agent rules for a specific agent.\n * Rules instruct the agent to proactively use memorix for context continuity.\n */\nasync function installAgentRules(agent: AgentName, projectRoot: string): Promise<void> {\n const rulesContent = getAgentRulesContent(agent);\n let rulesPath: string;\n\n switch (agent) {\n case 'windsurf':\n rulesPath = path.join(projectRoot, '.windsurf', 'rules', 'memorix.md');\n break;\n case 'cursor':\n rulesPath = path.join(projectRoot, '.cursor', 'rules', 'memorix.mdc');\n break;\n case 'claude':\n case 'copilot':\n rulesPath = path.join(projectRoot, '.github', 'copilot-instructions.md');\n break;\n case 'codex':\n rulesPath = path.join(projectRoot, 'AGENTS.md');\n break;\n case 'kiro':\n rulesPath = path.join(projectRoot, '.kiro', 'steering', 'memorix.md');\n break;\n case 'opencode':\n // OpenCode reads AGENTS.md (same as Codex), also supports CLAUDE.md as fallback\n rulesPath = path.join(projectRoot, 'AGENTS.md');\n break;\n case 'antigravity':\n // Gemini CLI reads context from GEMINI.md by default (like Codex reads AGENTS.md)\n // See: context.fileName defaults to [\"GEMINI.md\", \"CONTEXT.md\"]\n rulesPath = path.join(projectRoot, 'GEMINI.md');\n break;\n case 'trae':\n rulesPath = path.join(projectRoot, '.trae', 'rules', 'project_rules.md');\n break;\n default:\n rulesPath = path.join(projectRoot, '.agent', 'rules', 'memorix.md');\n break;\n }\n\n try {\n await fs.mkdir(path.dirname(rulesPath), { recursive: true });\n\n if (agent === 'codex' || agent === 'opencode' || agent === 'antigravity') {\n // For shared context files (AGENTS.md / GEMINI.md), append rather than overwrite\n try {\n const existing = await fs.readFile(rulesPath, 'utf-8');\n if (existing.includes('Memorix')) {\n return; // Already contains memorix rules\n }\n // Append to existing file\n await fs.writeFile(rulesPath, existing + '\\n\\n' + rulesContent, 'utf-8');\n } catch {\n // File doesn't exist, create it\n await fs.writeFile(rulesPath, rulesContent, 'utf-8');\n }\n } else {\n // Only write if not already present\n try {\n await fs.access(rulesPath);\n // File exists — don't overwrite user customizations\n } catch {\n await fs.writeFile(rulesPath, rulesContent, 'utf-8');\n }\n }\n } catch { /* silent */ }\n}\n\n/**\n * Get the memorix agent rules content.\n * Windsurf requires YAML frontmatter with trigger mode.\n * Cursor .mdc files use a similar frontmatter format.\n */\nfunction getAgentRulesContent(agent?: AgentName): string {\n let frontmatter = '';\n if (agent === 'windsurf') {\n frontmatter = `---\ntrigger: always_on\n---\n\n`;\n } else if (agent === 'cursor') {\n frontmatter = `---\ndescription: Memorix automatic memory recording rules\nalwaysApply: true\n---\n\n`;\n }\n return `${frontmatter}# Memorix — Automatic Memory Rules\n\nYou have access to Memorix memory tools. Follow these rules to maintain persistent context across sessions.\n\n## RULE 1: Session Start — Load Context\n\nAt the **beginning of every conversation**, BEFORE responding to the user:\n\n1. Call \\`memorix_session_start\\` to get the previous session summary and key memories (this is a direct read, not a search — no fragmentation risk)\n2. Then call \\`memorix_search\\` with a query related to the user's first message for additional context\n3. If search results are found, use \\`memorix_detail\\` to fetch the most relevant ones\n4. Reference relevant memories naturally — the user should feel you \"remember\" them\n\n## RULE 2: Store Important Context\n\n**Proactively** call \\`memorix_store\\` when any of the following happen:\n\n### What MUST be recorded:\n- Architecture/design decisions → type: \\`decision\\`\n- Bug identified and fixed → type: \\`problem-solution\\`\n- Unexpected behavior or gotcha → type: \\`gotcha\\`\n- Config changed (env vars, ports, deps) → type: \\`what-changed\\`\n- Feature completed or milestone → type: \\`what-changed\\`\n- Trade-off discussed with conclusion → type: \\`trade-off\\`\n\n### What should NOT be recorded:\n- Simple file reads, greetings, trivial commands (ls, pwd, git status)\n\n### Use topicKey for evolving topics:\nFor decisions, architecture docs, or any topic that evolves over time, ALWAYS use \\`topicKey\\` parameter.\nThis ensures the memory is UPDATED instead of creating duplicates.\nUse \\`memorix_suggest_topic_key\\` to generate a stable key.\n\nExample: \\`topicKey: \"architecture/auth-model\"\\` — subsequent stores with the same key update the existing memory.\n\n### Track progress with the progress parameter:\nWhen working on features or tasks, include the \\`progress\\` parameter:\n\\`\\`\\`json\n{\n \"progress\": {\n \"feature\": \"user authentication\",\n \"status\": \"in-progress\",\n \"completion\": 60\n }\n}\n\\`\\`\\`\nStatus values: \\`in-progress\\`, \\`completed\\`, \\`blocked\\`\n\n## RULE 3: Resolve Completed Memories\n\nWhen a task is completed, a bug is fixed, or information becomes outdated:\n\n1. Call \\`memorix_resolve\\` with the observation IDs to mark them as resolved\n2. Resolved memories are hidden from default search, preventing context pollution\n\nThis is critical — without resolving, old bug reports and completed tasks will keep appearing in future searches.\n\n## RULE 4: Session End — Store Decision Chain Summary\n\nWhen the conversation is ending, create a **decision chain summary** (not just a checklist):\n\n1. Call \\`memorix_store\\` with type \\`session-request\\` and \\`topicKey: \"session/latest-summary\"\\`:\n\n **Required structure:**\n \\`\\`\\`\n ## Goal\n [What we were working on — specific, not vague]\n\n ## Key Decisions & Reasoning\n - Chose X because Y. Rejected Z because [reason].\n - [Every architectural/design decision with WHY]\n\n ## What Changed\n - [File path] — [what changed and why]\n\n ## Current State\n - [What works now, what's pending]\n - [Any blockers or risks]\n\n ## Next Steps\n - [Concrete next actions, in priority order]\n \\`\\`\\`\n\n **Critical: Include the \"Key Decisions & Reasoning\" section.** Without it, the next AI session will lack the context to understand WHY things were done a certain way and may suggest conflicting approaches.\n\n2. Call \\`memorix_resolve\\` on any memories for tasks completed in this session\n\n## RULE 5: Compact Awareness\n\nMemorix automatically compacts memories on store:\n- **With LLM API configured:** Smart dedup — extracts facts, compares with existing, merges or skips duplicates\n- **Without LLM (free mode):** Heuristic dedup — uses similarity scores to detect and merge duplicate memories\n- **You don't need to manually deduplicate.** Just store naturally and compact handles the rest.\n- If you notice excessive duplicate memories, call \\`memorix_deduplicate\\` for batch cleanup.\n\n## Guidelines\n\n- **Use concise titles** (~5-10 words) and structured facts\n- **Include file paths** in filesModified when relevant\n- **Include related concepts** for better searchability\n- **Always use topicKey** for recurring topics to prevent duplicates\n- **Always resolve** completed tasks and fixed bugs\n- **Always include reasoning** — \"chose X because Y\" is 10x more valuable than \"did X\"\n- Search defaults to \\`status=\"active\"\\` — use \\`status=\"all\"\\` to include resolved memories\n`;\n}\n\n/**\n * Uninstall hooks for a specific agent.\n */\nexport async function uninstallHooks(\n agent: AgentName,\n projectRoot: string,\n global = false,\n): Promise<boolean> {\n const configPath = global\n ? getGlobalConfigPath(agent)\n : getProjectConfigPath(agent, projectRoot);\n\n try {\n if (agent === 'kiro') {\n await fs.unlink(configPath);\n } else {\n // For JSON configs, remove the hooks key\n const content = await fs.readFile(configPath, 'utf-8');\n const config = JSON.parse(content);\n delete config.hooks;\n\n if (Object.keys(config).length === 0) {\n await fs.unlink(configPath);\n } else {\n await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');\n }\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check hook installation status for all agents.\n */\nexport async function getHookStatus(\n projectRoot: string,\n): Promise<Array<{ agent: AgentName; installed: boolean; configPath: string }>> {\n const results: Array<{ agent: AgentName; installed: boolean; configPath: string }> = [];\n const agents: AgentName[] = ['claude', 'copilot', 'windsurf', 'cursor', 'kiro', 'codex', 'antigravity', 'opencode', 'trae'];\n\n for (const agent of agents) {\n const projectPath = getProjectConfigPath(agent, projectRoot);\n const globalPath = getGlobalConfigPath(agent);\n\n let installed = false;\n let usedPath = projectPath;\n\n try {\n await fs.access(projectPath);\n installed = true;\n } catch {\n try {\n await fs.access(globalPath);\n installed = true;\n usedPath = globalPath;\n } catch { /* not installed */ }\n }\n\n results.push({ agent, installed, configPath: usedPath });\n }\n\n return results;\n}\n","#!/usr/bin/env node\n\n/**\n * Memorix — Cross-Agent Memory Bridge\n *\n * Entry point for the MCP Server.\n * Connects via stdio transport for compatibility with all MCP-supporting agents.\n *\n * Usage:\n * node dist/index.js # Start as MCP server (stdio)\n * memorix init # CLI: Initialize project (P1)\n * memorix sync # CLI: Sync rules across agents (P2)\n */\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { createMemorixServer } from './server.js';\n\nasync function main(): Promise<void> {\n const { server, projectId, deferredInit } = await createMemorixServer();\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error(`[memorix] MCP Server running on stdio (project: ${projectId})`);\n deferredInit().catch(e => console.error(`[memorix] Deferred init error:`, e));\n}\n\nmain().catch((error) => {\n console.error('[memorix] Fatal error:', error);\n process.exit(1);\n});\n","/**\n * Memorix MCP Server\n *\n * Registers all MCP tools and handles the server lifecycle.\n *\n * Tool sources:\n * - memorix_store / memorix_search / memorix_detail / memorix_timeline:\n * Memorix extensions using claude-mem's 3-layer Progressive Disclosure\n * - create_entities / create_relations / add_observations / delete_entities /\n * delete_observations / delete_relations / search_nodes / open_nodes / read_graph:\n * MCP Official Memory Server compatible interface (P1)\n *\n * Extensibility:\n * - New tools can be registered via server.registerTool()\n * - Rules sync tools will be added in P2\n * - New agent format adapters plug in without changing this file\n */\n\nimport { watchFile } from 'node:fs';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { KnowledgeGraphManager } from './memory/graph.js';\nimport { initObservations, storeObservation, reindexObservations, migrateProjectIds, getObservation } from './memory/observations.js';\nimport { resetDb } from './store/orama-store.js';\nimport { createAutoRelations } from './memory/auto-relations.js';\nimport { extractEntities } from './memory/entity-extractor.js';\nimport { compactSearch, compactTimeline, compactDetail } from './compact/engine.js';\nimport { detectProject } from './project/detector.js';\nimport { registerAlias, initAliasRegistry, resolveAliases, autoMergeByBaseName } from './project/aliases.js';\nimport { getProjectDataDir } from './store/persistence.js';\nimport type { ObservationType, RuleSource, AgentTarget, MCPServerEntry } from './types.js';\nimport { RulesSyncer } from './rules/syncer.js';\nimport { WorkspaceSyncEngine } from './workspace/engine.js';\nimport { initLLM, isLLMEnabled, getLLMConfig } from './llm/provider.js';\nimport { compactOnWrite, deduplicateMemory } from './llm/memory-manager.js';\nimport type { ExistingMemory } from './llm/memory-manager.js';\n\n/** Timestamp of last MCP-initiated write — hot-reload skips changes within 10s */\nlet lastInternalWriteMs = 0;\nconst markInternalWrite = () => { lastInternalWriteMs = Date.now(); };\n\n/** Valid observation types for input validation */\nconst OBSERVATION_TYPES: [string, ...string[]] = [\n 'session-request',\n 'gotcha',\n 'problem-solution',\n 'how-it-works',\n 'what-changed',\n 'discovery',\n 'why-it-exists',\n 'decision',\n 'trade-off',\n];\n\n/**\n * Defensive parameter coercion for Claude Code CLI + non-Anthropic models (e.g. GLM).\n * Claude Code CLI has a known bug (#5504, #26027) where JSON objects/arrays\n * get serialized as strings. GLM models amplify this by producing string-encoded\n * arrays/numbers in tool calls. These helpers ensure Memorix works regardless.\n */\nfunction coerceNumberArray(val: unknown): number[] {\n if (Array.isArray(val)) return val.map(Number);\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (Array.isArray(parsed)) return parsed.map(Number);\n } catch { /* not valid JSON */ }\n }\n return [];\n}\n\nfunction coerceNumber(val: unknown, fallback: number): number {\n if (typeof val === 'number') return val;\n if (typeof val === 'string') {\n const n = Number(val);\n if (!Number.isNaN(n)) return n;\n }\n return fallback;\n}\n\nfunction coerceStringArray(val: unknown): string[] {\n if (Array.isArray(val)) return val.map(String);\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (Array.isArray(parsed)) return parsed.map(String);\n } catch { /* not valid JSON */ }\n }\n return [];\n}\n\nfunction coerceObject<T>(val: unknown): T | null {\n if (typeof val === 'object' && val !== null && !Array.isArray(val)) return val as T;\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (typeof parsed === 'object' && parsed !== null) return parsed as T;\n } catch { /* not valid JSON */ }\n }\n return null;\n}\n\nfunction coerceObjectArray<T>(val: unknown): T[] {\n if (Array.isArray(val)) {\n return val.map(item => {\n if (typeof item === 'string') {\n try { return JSON.parse(item); } catch { return item; }\n }\n return item;\n });\n }\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* not valid JSON */ }\n }\n return [];\n}\n\n/**\n * Create and configure the Memorix MCP Server.\n */\n/** Optional shared team instances — passed by serve-http so all sessions share state */\nexport interface SharedTeamInstances {\n registry: InstanceType<typeof import('./team/registry.js').AgentRegistry>;\n messageBus: InstanceType<typeof import('./team/messages.js').MessageBus>;\n fileLocks: InstanceType<typeof import('./team/file-locks.js').FileLockRegistry>;\n taskManager: InstanceType<typeof import('./team/tasks.js').TaskManager>;\n}\n\nexport async function createMemorixServer(cwd?: string, existingServer?: McpServer, sharedTeam?: SharedTeamInstances): Promise<{\n server: McpServer;\n graphManager: KnowledgeGraphManager;\n projectId: string;\n deferredInit: () => Promise<void>;\n}> {\n // Detect current project (never returns __invalid__ — degraded mode uses placeholder/)\n const rawProject = detectProject(cwd);\n\n // Migrate legacy per-project subdirectories into flat base directory (one-time, silent)\n try {\n const { migrateSubdirsToFlat } = await import('./store/persistence.js');\n const migrated = await migrateSubdirsToFlat();\n if (migrated) {\n console.error(`[memorix] Migrated per-project subdirectories into flat storage`);\n }\n } catch { /* migration is optional */ }\n\n const projectDir = await getProjectDataDir(rawProject.id);\n\n // Register alias and resolve to canonical project ID.\n // This ensures the same physical project always uses the same ID\n // regardless of which IDE or detection method discovered it.\n initAliasRegistry(projectDir);\n const canonicalId = await registerAlias(rawProject);\n const project = { ...rawProject, id: canonicalId };\n if (canonicalId !== rawProject.id) {\n console.error(`[memorix] Alias resolved: ${rawProject.id} → ${canonicalId}`);\n }\n\n // Initialize components\n const graphManager = new KnowledgeGraphManager(projectDir);\n await graphManager.init();\n await initObservations(projectDir);\n\n // Auto-merge obvious alias groups by scanning observed projectIds in data.\n // This detects splits like placeholder/foo + local/foo + user/foo\n try {\n const { getAllObservations } = await import('./memory/observations.js');\n const allObs = getAllObservations();\n const observedIds = [...new Set(allObs.map(o => o.projectId))];\n const merged = await autoMergeByBaseName(observedIds);\n if (merged > 0) {\n console.error(`[memorix] Auto-merged ${merged} alias group(s) by base name`);\n }\n } catch { /* auto-merge is optional */ }\n\n // Migrate existing observations to canonical project ID for ALL alias groups.\n // This normalizes split projectIds like placeholder/foo + local/foo → canonical.\n try {\n const { getAllAliasGroups } = await import('./project/aliases.js');\n const groups = await getAllAliasGroups();\n let totalMigrated = 0;\n for (const group of groups) {\n if (group.aliases.length > 1) {\n const migrated = await migrateProjectIds(group.aliases, group.canonical);\n if (migrated > 0) {\n console.error(`[memorix] Migrated ${migrated} observations → ${group.canonical}`);\n totalMigrated += migrated;\n }\n }\n }\n if (totalMigrated > 0) {\n console.error(`[memorix] Total migrated: ${totalMigrated} observations across ${groups.filter(g => g.aliases.length > 1).length} project(s)`);\n }\n } catch { /* migration is optional */ }\n\n // Reindex existing observations into Orama\n const reindexed = await reindexObservations();\n if (reindexed > 0) {\n console.error(`[memorix] Reindexed ${reindexed} observations for project: ${project.id}`);\n }\n\n // Initialize LLM provider (optional — graceful degradation)\n const llmConfig = initLLM();\n if (llmConfig) {\n console.error(`[memorix] LLM enhanced mode: ${llmConfig.provider}/${llmConfig.model}`);\n } else {\n console.error(`[memorix] LLM mode: off (set MEMORIX_LLM_API_KEY or OPENAI_API_KEY to enable)`);\n }\n\n console.error(`[memorix] Project: ${project.id} (${project.name})`);\n console.error(`[memorix] Data dir: ${projectDir}`);\n\n // Sync advisory variables — populated by deferredInit(), used by memorix_search\n let syncAdvisoryShown = false;\n let syncAdvisory: string | null = null;\n\n // Create MCP server (or use existing one from roots-aware flow)\n const server = existingServer ?? new McpServer({\n name: 'memorix',\n version: '0.1.0',\n });\n\n // ================================================================\n // Memorix Extended Tools (3-layer Progressive Disclosure)\n // ================================================================\n\n /**\n * memorix_store — Store a new observation\n *\n * Primary write API. Agents call this to persist knowledge.\n * Auto-assigns ID, counts tokens, indexes for search.\n */\n server.registerTool(\n 'memorix_store',\n {\n title: 'Store Memory',\n description:\n 'Store a new observation/memory. Automatically indexed for search. ' +\n 'Use type to classify: gotcha (🔴 critical pitfall), decision (🟤 architecture choice), ' +\n 'problem-solution (🟡 bug fix), how-it-works (🔵 explanation), what-changed (🟢 change), ' +\n 'discovery (🟣 insight), why-it-exists (🟠 rationale), trade-off (⚖️ compromise), ' +\n 'session-request (🎯 original goal). ' +\n 'Stored memories persist across sessions and are shared with other IDEs (Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, Trae) via the same local data directory.',\n inputSchema: {\n entityName: z.string().describe('The entity this observation belongs to (e.g., \"auth-module\", \"port-config\")'),\n type: z.enum(OBSERVATION_TYPES).describe('Observation type for classification'),\n title: z.string().describe('Short descriptive title (~5-10 words)'),\n narrative: z.string().describe('Full description of the observation'),\n facts: z.array(z.string()).optional().describe('Structured facts (e.g., \"Default timeout: 60s\")'),\n filesModified: z.array(z.string()).optional().describe('Files involved'),\n concepts: z.array(z.string()).optional().describe('Related concepts/keywords'),\n topicKey: z.string().optional().describe(\n 'Optional topic identifier for upserts (e.g., \"architecture/auth-model\"). ' +\n 'If an observation with the same topicKey already exists in this project, it will be UPDATED instead of creating a new one. ' +\n 'Use memorix_suggest_topic_key to generate a stable key. Good for evolving decisions, architecture docs, etc.',\n ),\n progress: z.object({\n feature: z.string().describe('Feature or task name'),\n status: z.enum(['in-progress', 'completed', 'blocked']).describe('Current status'),\n completion: z.number().optional().describe('Completion percentage 0-100'),\n }).optional().describe('Progress tracking for task/feature observations'),\n },\n },\n async ({ entityName, type, title, narrative, facts, filesModified, concepts, topicKey, progress }) => {\n // Defensive coercion: Claude Code CLI + GLM may send string-encoded arrays\n const safeFacts = facts ? coerceStringArray(facts) : undefined;\n const safeFiles = filesModified ? coerceStringArray(filesModified) : undefined;\n const safeConcepts = concepts ? coerceStringArray(concepts) : undefined;\n\n // ── Compact on Write (dual-mode: LLM or heuristic) ──────────────\n // Search for similar existing memories BEFORE storing.\n // If compact says UPDATE → merge into existing; NONE → skip storing.\n // This keeps memory count low and prevents duplication (Mem0-style).\n let compactAction = '';\n let compactMerged = false;\n if (!topicKey && !progress) {\n try {\n const searchResult = await compactSearch({\n query: `${title} ${narrative.substring(0, 200)}`,\n limit: 5,\n projectId: project.id,\n status: 'active',\n });\n const similarEntries = searchResult.entries.map(e => e);\n if (similarEntries.length > 0) {\n // Fetch full details for comparison\n const similarIds = similarEntries.map(e => e.id);\n const details = await compactDetail(similarIds);\n const existingMemories: ExistingMemory[] = details.documents.map((d, i) => ({\n id: d.observationId,\n title: d.title,\n narrative: d.narrative,\n facts: d.facts,\n score: similarEntries[i]?.score ?? 0,\n }));\n\n const decision = await compactOnWrite(\n { title, narrative, facts: safeFacts ?? [] },\n existingMemories,\n );\n\n if (decision.action === 'UPDATE' && decision.targetId) {\n // Merge into existing memory (Mem0-style UPDATE)\n const targetObs = getObservation(decision.targetId);\n if (targetObs) {\n markInternalWrite();\n await storeObservation({\n entityName: targetObs.entityName,\n type: targetObs.type,\n title: decision.mergedNarrative ? title : targetObs.title,\n narrative: decision.mergedNarrative ?? narrative,\n facts: decision.mergedFacts ?? safeFacts,\n filesModified: safeFiles,\n concepts: safeConcepts,\n projectId: project.id,\n topicKey: targetObs.topicKey,\n progress: progress as import('./types.js').ProgressInfo | undefined,\n });\n compactAction = `🔄 Compact UPDATE: merged into #${decision.targetId} (${decision.reason})`;\n compactMerged = true;\n\n // Return early — we updated existing, no new observation needed\n return {\n content: [{\n type: 'text' as const,\n text: `${compactAction}\\nMode: ${decision.usedLLM ? 'LLM' : 'heuristic'}`,\n }],\n };\n }\n } else if (decision.action === 'NONE') {\n // Memory is redundant — skip storing entirely\n return {\n content: [{\n type: 'text' as const,\n text: `⏭️ Compact SKIP: ${decision.reason}\\nExisting memory #${decision.targetId} already covers this.\\nMode: ${decision.usedLLM ? 'LLM' : 'heuristic'}`,\n }],\n };\n } else if (decision.action === 'DELETE' && decision.targetId) {\n // Old memory is outdated — resolve it, then ADD the new one\n const { resolveObservations } = await import('./memory/observations.js');\n await resolveObservations([decision.targetId], 'resolved');\n compactAction = ` | Compact: resolved outdated #${decision.targetId}`;\n }\n // decision.action === 'ADD' or DELETE fallthrough → proceed to store normally\n if (decision.enrichedFacts && decision.enrichedFacts.length > 0) {\n // LLM extracted additional facts — merge them in\n const currentFacts = safeFacts ?? [];\n const newFacts = decision.enrichedFacts.filter((f: string) => !currentFacts.includes(f));\n if (newFacts.length > 0) {\n compactAction += ` | +${newFacts.length} LLM-extracted facts`;\n }\n }\n }\n } catch { /* compact is best-effort */ }\n }\n\n // ── Standard store flow ─────────────────────────────────────────\n // Ensure entity exists in knowledge graph\n await graphManager.createEntities([\n { name: entityName, entityType: 'auto', observations: [] },\n ]);\n\n // Auto-associate sessionId from active session\n let sessionId: string | undefined;\n try {\n const { getActiveSession } = await import('./memory/session.js');\n const active = await getActiveSession(projectDir, project.id);\n if (active) sessionId = active.id;\n } catch { /* session module not critical */ }\n\n // ── LLM Narrative Compression (premium quality) ─────────────────\n // Compress verbose narratives into concise core knowledge before storing.\n // Reduces token consumption ~60% while preserving all technical facts.\n let finalNarrative = narrative;\n let compressionNote = '';\n try {\n const { compressNarrative } = await import('./llm/quality.js');\n const { compressed, saved, usedLLM } = await compressNarrative(narrative, safeFacts, type);\n if (usedLLM && saved > 0) {\n finalNarrative = compressed;\n compressionNote = ` | compressed -${saved} tokens`;\n }\n } catch { /* compression is best-effort */ }\n\n // Store the observation (may upsert if topicKey matches existing)\n markInternalWrite();\n const { observation: obs, upserted } = await storeObservation({\n entityName,\n type: type as ObservationType,\n title,\n narrative: finalNarrative,\n facts: safeFacts,\n filesModified: safeFiles,\n concepts: safeConcepts,\n projectId: project.id,\n topicKey,\n sessionId,\n progress: progress as import('./types.js').ProgressInfo | undefined,\n });\n\n // Add a reference to the entity's observations\n await graphManager.addObservations([\n { entityName, contents: [`[#${obs.id}] ${title}`] },\n ]);\n\n // Implicit memory: auto-create relations from entity extraction\n const extracted = extractEntities([title, narrative, ...(safeFacts ?? [])].join(' '));\n const autoRelCount = await createAutoRelations(obs, extracted, graphManager);\n\n // Build enrichment summary\n const enrichmentParts: string[] = [];\n const autoFiles = obs.filesModified.filter((f: string) => !(safeFiles ?? []).includes(f));\n const autoConcepts = obs.concepts.filter((c: string) => !(safeConcepts ?? []).includes(c));\n if (autoFiles.length > 0) enrichmentParts.push(`+${autoFiles.length} files extracted`);\n if (autoConcepts.length > 0) enrichmentParts.push(`+${autoConcepts.length} concepts enriched`);\n if (autoRelCount > 0) enrichmentParts.push(`+${autoRelCount} relations auto-created`);\n if (obs.hasCausalLanguage) enrichmentParts.push('causal language detected');\n if (upserted) enrichmentParts.push(`topic upserted (rev ${obs.revisionCount ?? 1})`);\n const enrichment = enrichmentParts.length > 0 ? `\\nAuto-enriched: ${enrichmentParts.join(', ')}` : '';\n\n const action = upserted ? '🔄 Updated' : '✅ Stored';\n\n return {\n content: [\n {\n type: 'text' as const,\n text: `${action} observation #${obs.id} \"${title}\" (~${obs.tokens} tokens)\\nEntity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ''}${compactAction}${compressionNote}${enrichment}`,\n },\n ],\n };\n },\n );\n\n /**\n * memorix_suggest_topic_key — Suggest a stable topic key for upserts\n *\n * Use before memorix_store when you want evolving topics to upsert\n * into a single observation instead of creating duplicates.\n */\n server.registerTool(\n 'memorix_suggest_topic_key',\n {\n title: 'Suggest Topic Key',\n description:\n 'Suggest a stable topic_key for memory upserts. Use this before memorix_store when you want evolving topics ' +\n '(like architecture decisions, config docs) to update a single observation over time instead of creating duplicates. ' +\n 'Returns a key like \"architecture/auth-model\" or \"bug/timeout-in-api-gateway\".',\n inputSchema: {\n type: z.string().describe('Observation type (e.g., decision, architecture, bugfix, discovery)'),\n title: z.string().describe('Observation title — used to generate the stable key'),\n },\n },\n async ({ type: obsType, title }) => {\n const { suggestTopicKey } = await import('./memory/observations.js');\n const key = suggestTopicKey(obsType, title);\n\n if (!key) {\n return {\n content: [{ type: 'text' as const, text: 'Could not suggest topic_key from the given input. Provide a more descriptive title.' }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: 'text' as const, text: `Suggested topic_key: \\`${key}\\`\\n\\nUse this as the \\`topicKey\\` parameter in \\`memorix_store\\` to enable upsert behavior.` }],\n };\n },\n );\n\n /**\n * memorix_search — Layer 1: Compact index search\n *\n * Returns a lightweight table of matching observations.\n * ~50-100 tokens per result. Agent scans this to decide what to fetch.\n */\n server.registerTool(\n 'memorix_search',\n {\n title: 'Search Memory',\n description:\n 'Search project memory. Returns a compact index (~50-100 tokens/result). ' +\n 'Use memorix_detail to fetch full content for specific IDs. ' +\n 'Use memorix_timeline to see chronological context. ' +\n 'Searches across all observations stored from any IDE session — enabling cross-session and cross-agent context retrieval.',\n inputSchema: {\n query: z.string().describe('Search query (natural language or keywords)'),\n limit: z.number().optional().describe('Max results (default: 20)'),\n type: z.enum(OBSERVATION_TYPES).optional().describe('Filter by observation type'),\n maxTokens: z.number().optional().describe('Token budget — trim results to fit (0 = unlimited)'),\n scope: z.enum(['project', 'global']).optional().default('project').describe(\n 'Search scope: \"project\" (default) only searches current project, \"global\" searches all projects',\n ),\n since: z.string().optional().describe('Only return observations created after this date (ISO 8601 or natural like \"2025-01-15\")'),\n until: z.string().optional().describe('Only return observations created before this date (ISO 8601 or natural like \"2025-02-01\")'),\n status: z.enum(['active', 'resolved', 'archived', 'all']).optional().default('active').describe(\n 'Filter by memory status. \"active\" (default) shows current memories, \"all\" includes resolved/archived.',\n ),\n },\n },\n async ({ query, limit, type, maxTokens, scope, since, until, status }) => {\n const safeLimit = limit != null ? coerceNumber(limit, 20) : undefined;\n const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : undefined;\n const result = await compactSearch({\n query,\n limit: safeLimit,\n type: type as ObservationType | undefined,\n maxTokens: safeMaxTokens,\n since,\n until,\n // Default to project-scoped search to prevent cross-project pollution.\n // Use scope: 'global' to explicitly search all projects.\n projectId: scope === 'global' ? undefined : project.id,\n status: (status as 'active' | 'resolved' | 'archived' | 'all') ?? 'active',\n });\n\n // Append sync advisory on first search of the session\n let text = result.formatted;\n if (!syncAdvisoryShown && syncAdvisory) {\n text += syncAdvisory;\n syncAdvisoryShown = true;\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text,\n },\n ],\n };\n },\n );\n\n /**\n * memorix_resolve — Mark memories as resolved/completed\n *\n * Prevents resolved memories from polluting future searches.\n * Default search only returns 'active' memories.\n */\n server.registerTool(\n 'memorix_resolve',\n {\n title: 'Resolve Memories',\n description:\n 'Mark observations as resolved (completed/no longer active). ' +\n 'Resolved memories are hidden from default search but can still be found with status=\"all\". ' +\n 'Use this to mark completed tasks, fixed bugs, or outdated information so they don\\'t pollute future context.',\n inputSchema: {\n ids: z.array(z.number()).describe('Observation IDs to mark as resolved'),\n status: z.enum(['resolved', 'archived']).optional().default('resolved').describe(\n 'Target status: \"resolved\" (default, completed/done) or \"archived\" (permanently hidden)',\n ),\n },\n },\n async ({ ids, status }) => {\n const { resolveObservations } = await import('./memory/observations.js');\n const safeIds = (Array.isArray(ids) ? ids : [ids]).map(id => coerceNumber(id, 0)).filter(id => id > 0);\n const result = await resolveObservations(safeIds, (status as 'resolved' | 'archived') ?? 'resolved');\n\n const parts: string[] = [];\n if (result.resolved.length > 0) {\n parts.push(`✅ Resolved ${result.resolved.length} observation(s): #${result.resolved.join(', #')}`);\n }\n if (result.notFound.length > 0) {\n parts.push(`⚠️ Not found: #${result.notFound.join(', #')}`);\n }\n parts.push('\\nResolved memories are hidden from default search. Use status=\"all\" to include them.');\n\n return {\n content: [{ type: 'text' as const, text: parts.join('\\n') }],\n };\n },\n );\n\n /**\n * memorix_deduplicate — LLM-powered batch deduplication\n *\n * Scans active memories for duplicates/contradictions and auto-resolves them.\n * Requires LLM to be configured (MEMORIX_LLM_API_KEY or OPENAI_API_KEY).\n */\n server.registerTool(\n 'memorix_deduplicate',\n {\n title: 'Deduplicate Memories',\n description:\n 'Scan active memories for duplicates, contradictions, and outdated information using LLM analysis. ' +\n 'Automatically resolves redundant memories. Requires LLM to be configured ' +\n '(set MEMORIX_LLM_API_KEY or OPENAI_API_KEY environment variable). ' +\n 'Without LLM, falls back to basic similarity-based consolidation.',\n inputSchema: {\n query: z.string().optional().describe('Optional query to scope dedup to a topic (default: scan all)'),\n dryRun: z.boolean().optional().default(false).describe('Preview only — show what would be resolved without making changes'),\n },\n },\n async ({ query, dryRun }) => {\n const { getAllObservations, resolveObservations } = await import('./memory/observations.js');\n const allObs = getAllObservations().filter(o => (o.status ?? 'active') === 'active' && o.projectId === project.id);\n\n if (allObs.length < 2) {\n return { content: [{ type: 'text' as const, text: 'Not enough active memories to deduplicate.' }] };\n }\n\n if (!isLLMEnabled()) {\n return {\n content: [{\n type: 'text' as const,\n text: '⚠️ LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY to enable intelligent dedup.\\n\\n' +\n 'Tip: Use memorix_consolidate for basic similarity-based merging without LLM.',\n }],\n };\n }\n\n // If query provided, search for relevant memories; otherwise take latest 20\n let candidates: typeof allObs;\n if (query) {\n const searchResult = await compactSearch({ query, limit: 20, projectId: project.id, status: 'active' });\n const idSet = new Set(searchResult.entries.map(e => e.id));\n candidates = allObs.filter(o => idSet.has(o.id));\n } else {\n candidates = allObs.slice(-20);\n }\n\n if (candidates.length < 2) {\n return { content: [{ type: 'text' as const, text: 'Not enough memories in scope to deduplicate.' }] };\n }\n\n // Group by entity for focused dedup\n const byEntity = new Map<string, typeof candidates>();\n for (const obs of candidates) {\n const list = byEntity.get(obs.entityName) ?? [];\n list.push(obs);\n byEntity.set(obs.entityName, list);\n }\n\n const actions: string[] = [];\n const toResolve: number[] = [];\n\n for (const [entity, group] of byEntity) {\n if (group.length < 2) continue;\n\n // Compare each pair within entity group\n for (let i = 0; i < group.length; i++) {\n for (let j = i + 1; j < group.length; j++) {\n const newer = group[j];\n const older = group[i];\n try {\n const decision = await deduplicateMemory(\n { title: newer.title, narrative: newer.narrative, facts: newer.facts },\n [{ id: older.id, title: older.title, narrative: older.narrative, facts: older.facts.join('\\n') }],\n );\n if (decision && decision.action === 'UPDATE' && decision.targetId) {\n actions.push(`🔄 #${older.id} \"${older.title}\" → superseded by #${newer.id} (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\n toResolve.push(older.id);\n } else if (decision && decision.action === 'NONE') {\n actions.push(`🗑️ #${newer.id} \"${newer.title}\" → redundant (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\n toResolve.push(newer.id);\n } else if (decision && decision.action === 'DELETE') {\n actions.push(`❌ #${decision.targetId ?? older.id} → outdated (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\n toResolve.push(decision.targetId ?? older.id);\n }\n } catch (dedupErr) { actions.push(`⚠️ comparison failed: ${(dedupErr as Error)?.message ?? dedupErr}`); }\n }\n }\n }\n\n if (actions.length === 0) {\n return { content: [{ type: 'text' as const, text: `✅ Scanned ${candidates.length} memories across ${byEntity.size} entities — no duplicates found.` }] };\n }\n\n if (dryRun) {\n return {\n content: [{\n type: 'text' as const,\n text: `🔍 DRY RUN — ${actions.length} action(s) found:\\n\\n${actions.join('\\n')}\\n\\nRun with dryRun=false to apply.`,\n }],\n };\n }\n\n // Apply resolutions\n const unique = [...new Set(toResolve)];\n await resolveObservations(unique, 'resolved');\n\n return {\n content: [{\n type: 'text' as const,\n text: `🧹 Deduplicated: resolved ${unique.length} memory(ies)\\n\\n${actions.join('\\n')}`,\n }],\n };\n },\n );\n\n /**\n * memorix_timeline — Layer 2: Chronological context\n *\n * Shows observations before and after a specific anchor.\n * Helps agents understand the temporal context of an observation.\n */\n server.registerTool(\n 'memorix_timeline',\n {\n title: 'Memory Timeline',\n description:\n 'Get chronological context around a specific observation. ' +\n 'Shows what happened before and after the anchor observation.',\n inputSchema: {\n anchorId: z.number().describe('Observation ID to center the timeline on'),\n depthBefore: z.number().optional().describe('Number of observations before (default: 3)'),\n depthAfter: z.number().optional().describe('Number of observations after (default: 3)'),\n },\n },\n async ({ anchorId, depthBefore, depthAfter }) => {\n const safeAnchor = coerceNumber(anchorId, 0);\n const safeBefore = depthBefore != null ? coerceNumber(depthBefore, 3) : undefined;\n const safeAfter = depthAfter != null ? coerceNumber(depthAfter, 3) : undefined;\n const result = await compactTimeline(\n safeAnchor,\n undefined,\n safeBefore,\n safeAfter,\n );\n\n return {\n content: [\n {\n type: 'text' as const,\n text: result.formatted,\n },\n ],\n };\n },\n );\n\n /**\n * memorix_detail — Layer 3: Full observation details\n *\n * Fetch complete observation content by IDs.\n * Only call after filtering via memorix_search / memorix_timeline.\n * ~500-1000 tokens per observation.\n */\n server.registerTool(\n 'memorix_detail',\n {\n title: 'Memory Details',\n description:\n 'Fetch full observation details by IDs (~500-1000 tokens each). ' +\n 'Always use memorix_search first to find relevant IDs, then fetch only what you need.',\n inputSchema: {\n ids: z.array(z.number()).describe('Observation IDs to fetch (from memorix_search results)'),\n },\n },\n async ({ ids }) => {\n // Defensive coercion: Claude Code CLI + GLM may send \"[16]\" instead of [16]\n const safeIds = coerceNumberArray(ids);\n const result = await compactDetail(safeIds);\n\n return {\n content: [\n {\n type: 'text' as const,\n text: result.documents.length > 0\n ? result.formatted\n : `No observations found for IDs: ${safeIds.join(', ')}`,\n },\n ],\n };\n },\n );\n\n // ================================================================\n // Memorix Retention & Decay Tools (inspired by mcp-memory-service + MemCP)\n // ================================================================\n\n /**\n * memorix_retention — Memory retention status\n *\n * Shows which observations are active, stale, or candidates for archiving.\n * Uses exponential decay scoring from mcp-memory-service.\n */\n server.registerTool(\n 'memorix_retention',\n {\n title: 'Memory Retention Status & Archive',\n description:\n 'Show memory retention status or archive expired memories. ' +\n 'action=\"report\" (default): show active/stale/archive-candidate counts. ' +\n 'action=\"archive\": move expired observations to archive file (reversible). ' +\n 'Uses exponential decay scoring based on importance, age, and access patterns.',\n inputSchema: {\n action: z.enum(['report', 'archive']).optional().describe('Action: \"report\" (show status, default) or \"archive\" (move expired to archive)'),\n },\n },\n async (args: { action?: string }) => {\n const action = args.action ?? 'report';\n const { getRetentionSummary, getArchiveCandidates, rankByRelevance, archiveExpired } = await import('./memory/retention.js');\n const { search } = await import('@orama/orama');\n\n // Handle archive action\n if (action === 'archive') {\n const result = await archiveExpired(projectDir);\n if (result.archived === 0) {\n return {\n content: [{ type: 'text' as const, text: '✅ No expired observations to archive. All memories are within their retention period.' }],\n };\n }\n return {\n content: [{ type: 'text' as const, text: `🗄️ Archived ${result.archived} expired observations → observations.archived.json\\n${result.remaining} active observations remaining.\\n\\nArchived memories can be restored manually if needed.` }],\n };\n }\n\n // Report action (default) — use in-memory observations for reliable lookup\n // (Orama search with empty term is unreliable)\n const { getAllObservations } = await import('./memory/observations.js');\n const allObs = getAllObservations();\n const docs: import('./types.js').MemorixDocument[] = allObs.map(obs => ({\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n }));\n\n if (docs.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No observations found for this project.' }],\n };\n }\n\n const summary = getRetentionSummary(docs);\n const candidates = getArchiveCandidates(docs);\n const ranked = rankByRelevance(docs);\n\n // Format output\n const lines: string[] = [\n `## Memory Retention Status`,\n ``,\n `| Zone | Count |`,\n `|------|-------|`,\n `| Active | ${summary.active} |`,\n `| Stale | ${summary.stale} |`,\n `| Archive Candidates | ${summary.archiveCandidates} |`,\n `| Immune | ${summary.immune} |`,\n `| **Total** | **${docs.length}** |`,\n ``,\n ];\n\n if (candidates.length > 0) {\n lines.push(`### Archive Candidates (${candidates.length})`);\n lines.push(`| ID | Title | Age (days) | Access |`);\n lines.push(`|----|-------|-----------|--------|`);\n for (const c of candidates.slice(0, 10)) {\n const ageDays = Math.round(\n (Date.now() - new Date(c.createdAt).getTime()) / (1000 * 60 * 60 * 24),\n );\n lines.push(`| ${c.observationId} | ${c.title} | ${ageDays}d | ${c.accessCount ?? 0}× |`);\n }\n lines.push('');\n lines.push(`> 💡 Use \\`memorix_retention\\` with \\`action: \"archive\"\\` to move these to archive.`);\n lines.push('');\n }\n\n // Top 5 most relevant\n lines.push(`### Top 5 Most Relevant`);\n lines.push(`| ID | Title | Score | Decay | Access Boost |`);\n lines.push(`|----|-------|-------|-------|-------------|`);\n for (const r of ranked.slice(0, 5)) {\n const doc = docs.find((d) => d.observationId === r.observationId);\n lines.push(\n `| ${r.observationId} | ${doc?.title ?? '?'} | ${r.totalScore.toFixed(3)} | ${r.decayFactor.toFixed(3)} | ${r.accessBoost.toFixed(1)}× |`,\n );\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n // ================================================================\n // MCP Official Memory Server Compatible Tools (optional — 9 tools)\n // Enable via ~/.memorix/settings.json { \"knowledgeGraph\": true }\n // ================================================================\n\n let enableKG = false;\n try {\n const { homedir } = await import('node:os');\n const { join } = await import('node:path');\n const { readFile } = await import('node:fs/promises');\n const raw = await readFile(join(homedir(), '.memorix', 'settings.json'), 'utf-8');\n const s = JSON.parse(raw);\n if (s.knowledgeGraph === true) enableKG = true;\n } catch { /* no settings or parse error — default off */ }\n\n if (enableKG) {\n\n /** create_entities — MCP Official compatible */\n server.registerTool(\n 'create_entities',\n {\n title: 'Create Entities',\n description: 'Create multiple new entities in the knowledge graph',\n inputSchema: {\n entities: z.array(z.object({\n name: z.string().describe('The name of the entity'),\n entityType: z.string().describe('The type of the entity'),\n observations: z.array(z.string()).describe('Initial observations'),\n })),\n },\n },\n async ({ entities }) => {\n const safeEntities = coerceObjectArray<{ name: string; entityType: string; observations: string[] }>(entities);\n const result = await graphManager.createEntities(safeEntities);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n };\n },\n );\n\n /** create_relations — MCP Official compatible, enhanced with typed relation suggestions */\n server.registerTool(\n 'create_relations',\n {\n title: 'Create Relations',\n description:\n 'Create multiple new relations between entities in the knowledge graph. Relations should be in active voice. ' +\n 'Recommended relation types (from mcp-memory-service): causes, fixes, supports, opposes, contradicts, ' +\n 'depends_on, implements, extends, replaces, documents',\n inputSchema: {\n relations: z.array(z.object({\n from: z.string().describe('Source entity name'),\n to: z.string().describe('Target entity name'),\n relationType: z.string().describe('Type of relation (e.g., causes, fixes, supports, depends_on, implements)'),\n })),\n },\n },\n async ({ relations }) => {\n const safeRelations = coerceObjectArray<{ from: string; to: string; relationType: string }>(relations);\n const result = await graphManager.createRelations(safeRelations);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n };\n },\n );\n\n /** add_observations — MCP Official compatible */\n server.registerTool(\n 'add_observations',\n {\n title: 'Add Observations',\n description: 'Add new observations to existing entities in the knowledge graph',\n inputSchema: {\n observations: z.array(z.object({\n entityName: z.string().describe('Entity name to add observations to'),\n contents: z.array(z.string()).describe('Observation contents to add'),\n })),\n },\n },\n async ({ observations }) => {\n const safeObs = coerceObjectArray<{ entityName: string; contents: string[] }>(observations);\n const result = await graphManager.addObservations(safeObs);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n };\n },\n );\n\n /** delete_entities — MCP Official compatible */\n server.registerTool(\n 'delete_entities',\n {\n title: 'Delete Entities',\n description: 'Delete multiple entities and their associated relations from the knowledge graph',\n inputSchema: {\n entityNames: z.array(z.string()).describe('Entity names to delete'),\n },\n },\n async ({ entityNames }) => {\n const safeNames = coerceStringArray(entityNames);\n await graphManager.deleteEntities(safeNames);\n return {\n content: [{ type: 'text' as const, text: 'Entities deleted successfully' }],\n };\n },\n );\n\n /** delete_observations — MCP Official compatible */\n server.registerTool(\n 'delete_observations',\n {\n title: 'Delete Observations',\n description: 'Delete specific observations from entities in the knowledge graph',\n inputSchema: {\n deletions: z.array(z.object({\n entityName: z.string().describe('Entity containing the observations'),\n observations: z.array(z.string()).describe('Observations to delete'),\n })),\n },\n },\n async ({ deletions }) => {\n const safeDeletions = coerceObjectArray<{ entityName: string; observations: string[] }>(deletions);\n await graphManager.deleteObservations(safeDeletions);\n return {\n content: [{ type: 'text' as const, text: 'Observations deleted successfully' }],\n };\n },\n );\n\n /** delete_relations — MCP Official compatible */\n server.registerTool(\n 'delete_relations',\n {\n title: 'Delete Relations',\n description: 'Delete multiple relations from the knowledge graph',\n inputSchema: {\n relations: z.array(z.object({\n from: z.string(),\n to: z.string(),\n relationType: z.string(),\n })),\n },\n },\n async ({ relations }) => {\n const safeRelations = coerceObjectArray<{ from: string; to: string; relationType: string }>(relations);\n await graphManager.deleteRelations(safeRelations);\n return {\n content: [{ type: 'text' as const, text: 'Relations deleted successfully' }],\n };\n },\n );\n\n /** read_graph — MCP Official compatible */\n server.registerTool(\n 'read_graph',\n {\n title: 'Read Graph',\n description: 'Read the entire knowledge graph',\n inputSchema: {},\n },\n async () => {\n const graph = await graphManager.readGraph();\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(graph, null, 2) }],\n };\n },\n );\n\n /** search_nodes — MCP Official compatible (basic string search) */\n server.registerTool(\n 'search_nodes',\n {\n title: 'Search Nodes',\n description: 'Search for nodes in the knowledge graph based on a query',\n inputSchema: {\n query: z.string().describe('Search query to match against entity names, types, and observations'),\n },\n },\n async ({ query }) => {\n const graph = await graphManager.searchNodes(query);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(graph, null, 2) }],\n };\n },\n );\n\n /** open_nodes — MCP Official compatible */\n server.registerTool(\n 'open_nodes',\n {\n title: 'Open Nodes',\n description: 'Open specific nodes in the knowledge graph by their names',\n inputSchema: {\n names: z.array(z.string()).describe('Entity names to retrieve'),\n },\n },\n async ({ names }) => {\n const safeNames = coerceStringArray(names);\n const graph = await graphManager.openNodes(safeNames);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(graph, null, 2) }],\n };\n },\n );\n\n } // end if (enableKG)\n\n // ============================================================\n // Rules Sync Tool (P2 — Memorix differentiator)\n // ============================================================\n\n const RULE_SOURCES: [string, ...string[]] = ['cursor', 'claude-code', 'codex', 'windsurf', 'antigravity', 'copilot', 'kiro', 'opencode', 'trae'];\n\n /** memorix_rules_sync — scan, dedup, and generate rules across agents */\n server.registerTool(\n 'memorix_rules_sync',\n {\n title: 'Rules Sync',\n description:\n 'Scan project for agent rule files (Cursor, Claude Code, Codex, Windsurf, Antigravity, Copilot, Kiro, OpenCode, Trae), ' +\n 'deduplicate, detect conflicts, and optionally generate rules for a target agent format. ' +\n 'Without target: returns sync status report. With target: generates converted rule files.',\n inputSchema: {\n action: z.enum(['status', 'generate']).describe('Action: \"status\" for report, \"generate\" to produce target files'),\n target: z.enum(RULE_SOURCES).optional().describe('Target agent format for generation (required when action=generate)'),\n },\n },\n async ({ action, target }) => {\n const syncer = new RulesSyncer(project.rootPath);\n\n if (action === 'status') {\n const status = await syncer.syncStatus();\n const lines = [\n `## Rules Sync Status`,\n ``,\n `**Sources found:** ${status.sources.join(', ') || 'none'}`,\n `**Total rules:** ${status.totalRules}`,\n `**Unique rules:** ${status.uniqueRules}`,\n `**Conflicts:** ${status.conflicts.length}`,\n ];\n\n if (status.conflicts.length > 0) {\n lines.push('', '### Conflicts');\n for (const c of status.conflicts) {\n lines.push(`- **${c.ruleA.source}** \\`${c.ruleA.id}\\` vs **${c.ruleB.source}** \\`${c.ruleB.id}\\`: ${c.reason}`);\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n }\n\n // action === 'generate'\n if (!target) {\n return {\n content: [{ type: 'text' as const, text: 'Error: target is required for generate action' }],\n isError: true,\n };\n }\n\n const rules = await syncer.scanRules();\n const deduped = syncer.deduplicateRules(rules);\n const effectiveTarget = target === 'opencode' ? 'codex' : target;\n const files = syncer.generateForTarget(deduped, effectiveTarget as RuleSource);\n\n const lines = [\n `## Generated ${files.length} file(s) for ${target}`,\n '',\n ];\n for (const f of files) {\n lines.push(`### \\`${f.filePath}\\``, '```', f.content, '```', '');\n }\n lines.push('> Use these contents to create the rule files in your project.');\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n // ============================================================\n // Workspace Sync Tool (P3 — Cross-Agent Workspace Bridge)\n // ============================================================\n\n const AGENT_TARGETS: [string, ...string[]] = ['windsurf', 'cursor', 'claude-code', 'codex', 'copilot', 'antigravity', 'kiro', 'opencode', 'trae'];\n\n /** memorix_workspace_sync — migrate entire workspace config across agents */\n server.registerTool(\n 'memorix_workspace_sync',\n {\n title: 'Workspace Sync',\n description:\n 'Migrate your entire workspace environment between AI coding agents (Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, OpenCode, Trae). ' +\n 'Syncs MCP server configs, workflows, rules, and skills across IDEs. ' +\n 'Action \"scan\": detect all workspace configs. ' +\n 'Action \"migrate\": generate configs for target agent (preview only). ' +\n 'Action \"apply\": migrate AND write configs to disk with backup/rollback.',\n inputSchema: {\n action: z.enum(['scan', 'migrate', 'apply']).describe('Action: \"scan\" to detect configs, \"migrate\" to preview, \"apply\" to write to disk'),\n target: z.enum(AGENT_TARGETS).optional().describe('Target agent for migration (required for migrate)'),\n items: z.array(z.string()).optional().describe('Selective sync: list specific MCP server or skill names to sync (e.g. [\"figma-remote-mcp-server\", \"create-subagent\"]). Omit to sync all.'),\n },\n },\n async ({ action, target, items }) => {\n const engine = new WorkspaceSyncEngine(project.rootPath);\n\n if (action === 'scan') {\n const scan = await engine.scan();\n const lines = [\n `## Workspace Scan Report`,\n '',\n `### MCP Server Configs`,\n ];\n\n for (const [agent, servers] of Object.entries(scan.mcpConfigs)) {\n if ((servers as MCPServerEntry[]).length > 0) {\n lines.push(`- **${agent}**: ${(servers as MCPServerEntry[]).length} server(s) — ${(servers as MCPServerEntry[]).map((s: MCPServerEntry) => s.name).join(', ')}`);\n }\n }\n\n lines.push('', `### Workflows`);\n if (scan.workflows.length > 0) {\n for (const wf of scan.workflows) {\n lines.push(`- **${wf.name}** (${wf.source}): ${wf.description || '(no description)'}`);\n }\n } else {\n lines.push('- No workflows found');\n }\n\n lines.push('', `### Rules`);\n lines.push(`- ${scan.rulesCount} rule(s) detected across all agents`);\n\n lines.push('', `### Skills`);\n if (scan.skills.length > 0) {\n for (const sk of scan.skills) {\n lines.push(`- **${sk.name}** (${sk.sourceAgent}): ${sk.description || '(no description)'}`);\n }\n } else {\n lines.push('- No skills found');\n }\n\n if (scan.skillConflicts.length > 0) {\n lines.push('', `### ⚠️ Skill Name Conflicts`);\n for (const c of scan.skillConflicts) {\n lines.push(`- **${c.name}**: kept from ${c.kept.sourceAgent}, duplicate in ${c.skipped.sourceAgent}`);\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n }\n\n // action === 'migrate' or 'apply' — both need target\n if (!target) {\n return {\n content: [{ type: 'text' as const, text: 'Error: target is required for migrate/apply action' }],\n isError: true,\n };\n }\n\n if (action === 'apply') {\n const applyResult = await engine.apply(target as AgentTarget, items);\n return {\n content: [{ type: 'text' as const, text: applyResult.migrationSummary }],\n ...(applyResult.success ? {} : { isError: true }),\n };\n }\n\n // action === 'migrate' (preview only)\n const result = await engine.migrate(target as AgentTarget, items);\n const lines = [\n `## Workspace Migration → ${target}`,\n '',\n ];\n\n if (result.mcpServers.generated.length > 0) {\n lines.push('### MCP Config');\n for (const f of result.mcpServers.generated) {\n lines.push(`#### \\`${f.filePath}\\``, '```', f.content, '```', '');\n }\n }\n\n if (result.workflows.generated.length > 0) {\n lines.push('### Workflows');\n for (const f of result.workflows.generated) {\n lines.push(`#### \\`${f.filePath}\\``, '```', f.content, '```', '');\n }\n }\n\n if (result.rules.generated > 0) {\n lines.push(`### Rules`, `- ${result.rules.generated} rule file(s) generated`);\n }\n\n if (result.skills.scanned.length > 0) {\n lines.push('### Skills', `- ${result.skills.scanned.length} skill(s) found, ready to copy:`);\n for (const sk of result.skills.scanned) {\n lines.push(` - **${sk.name}** (from ${sk.sourceAgent})`);\n }\n }\n\n lines.push('', '> Review the generated configs above. Use action \"apply\" to write them to disk.');\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n // ============================================================\n // memorix_skills — Memory-driven project skills\n // ============================================================\n\n server.registerTool(\n 'memorix_skills',\n {\n title: 'Project Skills',\n description:\n 'Memory-driven project skills. ' +\n 'Action \"list\": show all available skills from all agents. ' +\n 'Action \"generate\": auto-generate project-specific skills from observation patterns (gotchas, decisions, how-it-works). ' +\n 'Action \"inject\": return a specific skill\\'s full content for direct use. ' +\n 'Generated skills follow the SKILL.md standard and can be synced across Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, OpenCode, and Trae.',\n inputSchema: {\n action: z.enum(['list', 'generate', 'inject']).describe('Action: \"list\" to discover skills, \"generate\" to create from memory, \"inject\" to get skill content'),\n name: z.string().optional().describe('Skill name (required for \"inject\")'),\n target: z.enum(AGENT_TARGETS).optional().describe('Target agent to write generated skills to (optional for \"generate\")'),\n write: z.boolean().optional().describe('Whether to write generated skills to disk (default: false, preview only)'),\n },\n },\n async ({ action, name, target, write }) => {\n const { SkillsEngine } = await import('./skills/engine.js');\n const engine = new SkillsEngine(project.rootPath);\n\n if (action === 'list') {\n const skills = engine.listSkills();\n if (skills.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No skills found in any agent directory.\\n\\nSkills are discovered from:\\n- `.cursor/skills/*/SKILL.md`\\n- `.agents/skills/*/SKILL.md`\\n- `.agent/skills/*/SKILL.md`\\n- `.windsurf/skills/*/SKILL.md`\\n- etc.\\n\\nUse action \"generate\" to auto-create skills from your project observations.' }],\n };\n }\n\n const lines = [\n `## Available Skills (${skills.length})`,\n '',\n ];\n for (const sk of skills) {\n lines.push(`- **${sk.name}** (${sk.sourceAgent}): ${sk.description || '(no description)'}`);\n }\n lines.push('', '> Use `action: \"inject\", name: \"<skill-name>\"` to get full skill content.');\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n }\n\n if (action === 'inject') {\n if (!name) {\n return {\n content: [{ type: 'text' as const, text: 'Error: `name` is required for inject action. Use `action: \"list\"` first to see available skills.' }],\n isError: true,\n };\n }\n\n const skill = engine.injectSkill(name);\n if (!skill) {\n return {\n content: [{ type: 'text' as const, text: `Skill \"${name}\" not found. Use \\`action: \"list\"\\` to see available skills.` }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: 'text' as const, text: `## Skill: ${skill.name}\\n**Source**: ${skill.sourceAgent}\\n**Path**: ${skill.sourcePath}\\n\\n---\\n\\n${skill.content}` }],\n };\n }\n\n // action === 'generate'\n const { loadObservationsJson } = await import('./store/persistence.js');\n const allObs = await loadObservationsJson(projectDir) as Array<{\n id?: number; entityName?: string; type?: string; title?: string;\n narrative?: string; facts?: string[]; concepts?: string[];\n filesModified?: string[]; createdAt?: string;\n }>;\n\n const obsData = allObs.map(o => ({\n id: o.id || 0,\n entityName: o.entityName || 'unknown',\n type: o.type || 'discovery',\n title: o.title || '',\n narrative: o.narrative || '',\n facts: o.facts,\n concepts: o.concepts,\n filesModified: o.filesModified,\n createdAt: o.createdAt,\n }));\n\n const generated = engine.generateFromObservations(obsData);\n\n if (generated.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No skill-worthy patterns found yet.\\n\\nSkills are auto-generated when entities accumulate enough observations (3+), especially gotchas, decisions, and how-it-works notes.\\n\\nKeep using memorix_store to build up project knowledge!' }],\n };\n }\n\n const lines = [\n `## Generated Skills (${generated.length})`,\n '',\n 'Based on observation patterns in your project memory:',\n '',\n ];\n\n for (const sk of generated) {\n lines.push(`### ${sk.name}`);\n lines.push(`- **Description**: ${sk.description}`);\n lines.push(`- **Observations**: ${sk.content.split('\\n').length} lines of knowledge`);\n\n if (write && target) {\n const path = engine.writeSkill(sk, target as AgentTarget);\n if (path) {\n lines.push(`- ✅ **Written**: \\`${path}\\``);\n } else {\n lines.push(`- ❌ Failed to write`);\n }\n }\n lines.push('');\n }\n\n if (!write) {\n lines.push('> Preview only. Add `write: true, target: \"<agent>\"` to save skills to disk.');\n }\n\n // Show first generated skill as preview\n if (generated.length > 0) {\n lines.push('', '---', '### Preview: ' + generated[0].name, '', '```markdown', generated[0].content, '```');\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n // ============================================================\n // Mini-Skills — Promote memories to permanent skills\n // ============================================================\n\n /**\n * memorix_promote — Promote observations to permanent mini-skills\n *\n * Converts important memories into permanent, never-decaying mini-skills\n * that are automatically injected into agent context at session_start.\n */\n server.registerTool(\n 'memorix_promote',\n {\n title: 'Promote to Mini-Skill',\n description:\n 'Promote observations to permanent mini-skills that never decay and are auto-injected at session start. ' +\n 'Action \"promote\": convert observation(s) to a mini-skill. ' +\n 'Action \"list\": show all active mini-skills. ' +\n 'Action \"delete\": remove a mini-skill by ID.\\n\\n' +\n 'Mini-skills are project-specific specialized knowledge derived from your actual memories — ' +\n 'gotchas, decisions, fixes that generic online skills cannot provide.',\n inputSchema: {\n action: z.enum(['promote', 'list', 'delete']).describe('Action to perform'),\n observationIds: z.array(z.number()).optional().describe('Observation IDs to promote (required for \"promote\")'),\n skillId: z.number().optional().describe('Mini-skill ID to delete (required for \"delete\")'),\n trigger: z.string().optional().describe('Override: when this skill should be applied'),\n instruction: z.string().optional().describe('Override: what the agent should do'),\n tags: z.array(z.string()).optional().describe('Extra classification tags'),\n },\n },\n async ({ action, observationIds, skillId, trigger, instruction, tags }) => {\n const { promoteToMiniSkill, loadAllMiniSkills, deleteMiniSkill, formatMiniSkillsForInjection } = await import('./skills/mini-skills.js');\n\n if (action === 'list') {\n const skills = await loadAllMiniSkills(projectDir);\n if (skills.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No mini-skills found.\\n\\nUse `action: \"promote\", observationIds: [<id>]` to convert important memories into permanent mini-skills.\\nThese will be auto-injected at every session start.' }],\n };\n }\n const formatted = formatMiniSkillsForInjection(skills);\n const lines = [\n formatted,\n '---',\n `Total: ${skills.length} mini-skill(s)`,\n '',\n '> Use `action: \"delete\", skillId: <id>` to remove a mini-skill.',\n ];\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n }\n\n if (action === 'delete') {\n if (skillId == null) {\n return { content: [{ type: 'text' as const, text: 'Error: `skillId` is required for delete action.' }], isError: true };\n }\n const deleted = await deleteMiniSkill(projectDir, skillId);\n if (!deleted) {\n return { content: [{ type: 'text' as const, text: `Mini-skill #${skillId} not found.` }], isError: true };\n }\n return { content: [{ type: 'text' as const, text: `✅ Deleted mini-skill #${skillId}.` }] };\n }\n\n // action === 'promote'\n if (!observationIds || observationIds.length === 0) {\n return { content: [{ type: 'text' as const, text: 'Error: `observationIds` is required for promote action. Use `memorix_search` to find observation IDs.' }], isError: true };\n }\n\n // Load observations by ID\n const { getAllObservations } = await import('./memory/observations.js');\n const allObs = getAllObservations();\n const selected = allObs.filter(o => observationIds.includes(o.id));\n\n if (selected.length === 0) {\n return { content: [{ type: 'text' as const, text: `No observations found for IDs: [${observationIds.join(', ')}]. Use \\`memorix_search\\` to find valid IDs.` }], isError: true };\n }\n\n const skill = await promoteToMiniSkill(projectDir, project.id, selected, { trigger, instruction, tags });\n\n const lines = [\n `✅ Created mini-skill #${skill.id}`,\n '',\n `**${skill.title}**`,\n `**Do**: ${skill.instruction}`,\n `**When**: ${skill.trigger}`,\n ];\n if (skill.facts.length > 0) {\n lines.push('**Facts**:');\n for (const f of skill.facts) lines.push(`- ${f}`);\n }\n lines.push('', `Source: ${selected.length} observation(s) [${selected.map(o => o.id).join(', ')}]`);\n lines.push('', '> This mini-skill will be auto-injected at every `memorix_session_start`.');\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n },\n );\n\n // ============================================================\n // Memory Consolidation\n // ============================================================\n\n /**\n * memorix_consolidate — Merge similar observations to reduce bloat\n */\n server.registerTool(\n 'memorix_consolidate',\n {\n title: 'Consolidate Memories',\n description:\n 'Find and merge similar observations to reduce memory bloat. ' +\n 'Uses text similarity to cluster related observations by entity+type, then merges them into single consolidated records. ' +\n 'Use action=\"preview\" to see candidates without changing data, action=\"execute\" to merge.\\n\\n' +\n 'Example: 10 similar gotchas about Windows paths → 1 consolidated gotcha with all facts preserved.',\n inputSchema: {\n action: z.enum(['preview', 'execute']).describe('preview = dry run showing candidates, execute = actually merge'),\n threshold: z.number().optional().describe('Similarity threshold 0.0-1.0 (default: 0.45). Lower = more aggressive merging'),\n },\n },\n async ({ action, threshold }) => {\n const safeThreshold = threshold != null ? coerceNumber(threshold, 0.45) : undefined;\n const { findConsolidationCandidates, executeConsolidation } = await import('./memory/consolidation.js');\n\n if (action === 'preview') {\n const clusters = await findConsolidationCandidates(projectDir, project.id, { threshold: safeThreshold });\n\n if (clusters.length === 0) {\n return { content: [{ type: 'text' as const, text: '✅ No consolidation candidates found. Your memories are already clean!' }] };\n }\n\n const lines = [`## Consolidation Preview`, `Found **${clusters.length}** clusters to merge:`, ''];\n for (let i = 0; i < clusters.length; i++) {\n const c = clusters[i];\n lines.push(`### Cluster ${i + 1} (${c.ids.length} observations, ~${(c.similarity * 100).toFixed(0)}% similar)`);\n lines.push(`Entity: \\`${c.entityName}\\` | Type: ${c.type}`);\n for (const title of c.titles) lines.push(`- ${title}`);\n lines.push('');\n }\n const totalMergeable = clusters.reduce((sum, c) => sum + c.ids.length - 1, 0);\n lines.push(`> Run with \\`action: \"execute\"\\` to merge. This will remove **${totalMergeable}** duplicate observations.`);\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n }\n\n // Execute\n const result = await executeConsolidation(projectDir, project.id, { threshold: safeThreshold });\n\n if (result.clustersFound === 0) {\n return { content: [{ type: 'text' as const, text: '✅ No consolidation needed. Memories are already clean!' }] };\n }\n\n const lines = [\n `## Consolidation Complete`,\n `- Clusters merged: **${result.clustersFound}**`,\n `- Observations removed: **${result.observationsMerged}**`,\n `- Observations remaining: **${result.observationsAfter}**`,\n '',\n ];\n for (const m of result.merges) {\n lines.push(`- Merged [${m.mergedIds.join(', ')}] → \"${m.resultTitle}\" (${m.factCount} facts)`);\n }\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n },\n );\n\n // ============================================================\n // Session Lifecycle Tools (inspired by Engram)\n // ============================================================\n\n /**\n * memorix_session_start — Start a new coding session\n *\n * Creates a session record and returns context from previous sessions.\n * This is the entry point for session-aware memory management.\n */\n server.registerTool(\n 'memorix_session_start',\n {\n title: 'Start Session',\n description:\n 'Start a new coding session. Returns context from previous sessions so you can resume work seamlessly. ' +\n 'Call this at the beginning of a session to track activity and get injected context. ' +\n 'Any previous active session for this project will be auto-closed.',\n inputSchema: {\n sessionId: z.string().optional().describe('Custom session ID (auto-generated if omitted)'),\n agent: z.string().optional().describe('Agent/IDE name (e.g., \"cursor\", \"windsurf\", \"claude-code\")'),\n },\n },\n async ({ sessionId, agent }) => {\n const { startSession } = await import('./memory/session.js');\n const result = await startSession(projectDir, project.id, { sessionId, agent });\n\n const llmStatus = isLLMEnabled()\n ? `LLM enhanced mode: ${getLLMConfig()?.provider}/${getLLMConfig()?.model} (fact extraction + auto-dedup active)`\n : 'LLM mode: off (set MEMORIX_LLM_API_KEY to enable enhanced memory quality)';\n\n const lines = [\n `✅ Session started: ${result.session.id}`,\n `Project: ${project.name} (${project.id})`,\n result.session.agent ? `Agent: ${result.session.agent}` : '',\n llmStatus,\n '',\n '💡 Tips: Use `memorix_resolve` to mark completed tasks. Use `progress` param in `memorix_store` for task tracking. Use `topicKey` to prevent duplicate memories.',\n '',\n ];\n\n // Inject mini-skills (permanent, never-decaying project knowledge)\n try {\n const { loadAllMiniSkills, formatMiniSkillsForInjection, recordMiniSkillUsage } = await import('./skills/mini-skills.js');\n const miniSkills = await loadAllMiniSkills(projectDir);\n if (miniSkills.length > 0) {\n const formatted = formatMiniSkillsForInjection(miniSkills);\n lines.push('---', '', formatted);\n // Record usage asynchronously (don't block response)\n recordMiniSkillUsage(projectDir, miniSkills.map(s => s.id)).catch(() => {});\n }\n } catch { /* mini-skills not available yet — skip */ }\n\n if (result.previousContext) {\n lines.push('---', '📋 **Context from previous sessions:**', '', result.previousContext);\n } else {\n lines.push('No previous session context found. This appears to be a fresh project.');\n }\n\n // Inject team context if any agents are active\n try {\n const activeAgents = teamRegistry.listAgents({ status: 'active' });\n if (activeAgents.length > 0) {\n lines.push('', '---', '👥 **Team Status:**');\n for (const a of activeAgents) {\n lines.push(`- 🟢 ${a.name}${a.role ? ` (${a.role})` : ''}`);\n }\n\n // Show locked files\n fileLocks.cleanExpired();\n const locks = fileLocks.listLocks();\n if (locks.length > 0) {\n lines.push('', '🔒 **Locked files:**');\n for (const l of locks) {\n const owner = teamRegistry.getAgent(l.lockedBy);\n lines.push(`- ${l.file} — ${owner?.name ?? l.lockedBy.slice(0, 8)}`);\n }\n }\n\n lines.push('', '💡 Use `team_join` to register, `team_inbox` to check messages, `team_task_list available=true` for available work.');\n }\n } catch { /* team context injection is optional */ }\n\n return {\n content: [{ type: 'text' as const, text: lines.filter(Boolean).join('\\n') }],\n };\n },\n );\n\n /**\n * memorix_session_end — End the current coding session\n *\n * Marks the session as completed with a structured summary.\n */\n server.registerTool(\n 'memorix_session_end',\n {\n title: 'End Session',\n description:\n 'End a coding session with a structured summary. This summary will be injected into the next session ' +\n 'so the next agent can resume work seamlessly.\\n\\n' +\n 'Recommended summary format:\\n' +\n '## Goal\\n[What we were working on]\\n\\n' +\n '## Discoveries\\n- [Technical findings, gotchas, learnings]\\n\\n' +\n '## Accomplished\\n- ✅ [Completed tasks]\\n- 🔲 [Pending for next session]\\n\\n' +\n '## Relevant Files\\n- path/to/file — [what changed]',\n inputSchema: {\n sessionId: z.string().describe('Session ID to close (from memorix_session_start)'),\n summary: z.string().optional().describe('Structured session summary (Goal/Discoveries/Accomplished/Files format)'),\n },\n },\n async ({ sessionId, summary }) => {\n const { endSession } = await import('./memory/session.js');\n const session = await endSession(projectDir, sessionId, summary);\n\n if (!session) {\n return {\n content: [{ type: 'text' as const, text: `Session \"${sessionId}\" not found.` }],\n isError: true,\n };\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: `✅ Session \"${sessionId}\" completed.\\nDuration: ${session.startedAt} → ${session.endedAt}\\n${summary ? 'Summary saved for next session context injection.' : 'No summary provided — consider adding one for better cross-session context.'}`,\n }],\n };\n },\n );\n\n /**\n * memorix_session_context — Get context from previous sessions\n *\n * Use this for compaction recovery or to manually retrieve session history.\n */\n server.registerTool(\n 'memorix_session_context',\n {\n title: 'Session Context',\n description:\n 'Get context from previous coding sessions. Use this after compaction to recover lost context, ' +\n 'or to manually review session history. Returns previous session summaries and key observations.',\n inputSchema: {\n limit: z.number().optional().describe('Number of recent sessions to include (default: 3)'),\n },\n },\n async ({ limit }) => {\n const safeLimit = limit != null ? coerceNumber(limit, 3) : 3;\n const { getSessionContext, listSessions } = await import('./memory/session.js');\n const context = await getSessionContext(projectDir, project.id, safeLimit);\n const sessions = await listSessions(projectDir, project.id);\n\n const activeSessions = sessions.filter(s => s.status === 'active');\n const completedSessions = sessions.filter(s => s.status === 'completed');\n\n const header = [\n `## Session Stats`,\n `- Active: ${activeSessions.length}`,\n `- Completed: ${completedSessions.length}`,\n `- Total: ${sessions.length}`,\n '',\n ];\n\n if (!context) {\n return {\n content: [{ type: 'text' as const, text: header.join('\\n') + '\\nNo previous session context available.' }],\n };\n }\n\n return {\n content: [{ type: 'text' as const, text: header.join('\\n') + context }],\n };\n },\n );\n\n // ============================================================\n // Export / Import\n // ============================================================\n\n /**\n * memorix_transfer — Export or import project memories\n */\n server.registerTool(\n 'memorix_transfer',\n {\n title: 'Transfer Memories',\n description:\n 'Export or import project memories. ' +\n 'Action \"export\": export observations and sessions (JSON or Markdown). ' +\n 'Action \"import\": import from a JSON export (re-assigns IDs, skips duplicate topicKeys).',\n inputSchema: {\n action: z.enum(['export', 'import']).describe('Operation: export or import'),\n format: z.enum(['json', 'markdown']).optional().describe('Export format (for export, default: json)'),\n data: z.string().optional().describe('JSON string from a previous export (for import)'),\n },\n },\n async ({ action, format, data: jsonStr }) => {\n if (action === 'export') {\n const { exportAsJson, exportAsMarkdown } = await import('./memory/export-import.js');\n if (format === 'markdown') {\n const md = await exportAsMarkdown(projectDir, project.id);\n return { content: [{ type: 'text' as const, text: md }] };\n }\n const data = await exportAsJson(projectDir, project.id);\n const json = JSON.stringify(data, null, 2);\n return {\n content: [{\n type: 'text' as const,\n text: `Export complete — ${data.stats.observationCount} observations, ${data.stats.sessionCount} sessions\\n\\n\\`\\`\\`json\\n${json}\\n\\`\\`\\`\\n\\n> Use action \"import\" on another machine to restore.`,\n }],\n };\n }\n // import\n if (!jsonStr) return { content: [{ type: 'text' as const, text: '❌ data is required for import' }], isError: true };\n const { importFromJson } = await import('./memory/export-import.js');\n let parsed;\n try { parsed = JSON.parse(jsonStr); } catch {\n return { content: [{ type: 'text' as const, text: 'Invalid JSON. Provide the exact output from export.' }], isError: true };\n }\n const result = await importFromJson(projectDir, parsed);\n return {\n content: [{\n type: 'text' as const,\n text: `Import complete — ${result.observationsImported} observations, ${result.sessionsImported} sessions imported, ${result.skipped} skipped`,\n }],\n };\n },\n );\n\n // ============================================================\n // memorix_dashboard — Launch the web dashboard\n // ============================================================\n\n let dashboardRunning = false;\n\n server.registerTool(\n 'memorix_dashboard',\n {\n title: 'Launch Dashboard',\n description:\n 'Launch the Memorix Web Dashboard in the browser. ' +\n 'Shows knowledge graph, observations, retention scores, and project stats in a visual interface.',\n inputSchema: {\n port: z.number().optional().describe('Port to run the dashboard on (default: 3210)'),\n },\n },\n async ({ port: dashboardPort }) => {\n const portNum = dashboardPort != null ? coerceNumber(dashboardPort, 3210) : 3210;\n const url = `http://localhost:${portNum}`;\n\n if (dashboardRunning) {\n // Verify the dashboard is actually still listening (process may have been killed externally)\n const { createConnection } = await import('node:net');\n const isAlive = await new Promise<boolean>(resolve => {\n const sock = createConnection(portNum, '127.0.0.1');\n sock.once('connect', () => { sock.destroy(); resolve(true); });\n sock.once('error', () => { sock.destroy(); resolve(false); });\n setTimeout(() => { sock.destroy(); resolve(false); }, 1000);\n });\n\n if (isAlive) {\n // Update the dashboard server's current project via API\n const http = await import('node:http');\n const postData = JSON.stringify({ projectId: project.id, projectName: project.name });\n await new Promise<void>(resolve => {\n const req = http.request({\n hostname: '127.0.0.1', port: portNum,\n path: '/api/set-current-project', method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },\n }, () => resolve());\n req.on('error', () => resolve()); // ignore errors\n req.write(postData);\n req.end();\n });\n\n // Open browser — the dashboard now serves this project as current\n const projectUrl = `${url}?project=${encodeURIComponent(project.id)}`;\n const { exec } = await import('node:child_process');\n const cmd =\n process.platform === 'win32' ? `start \"\" \"${projectUrl}\"` :\n process.platform === 'darwin' ? `open \"${projectUrl}\"` :\n `xdg-open \"${projectUrl}\"`;\n exec(cmd, () => { });\n return {\n content: [{ type: 'text' as const, text: `Dashboard is already running at ${url}. Switched to project: ${project.name} (${project.id}).` }],\n };\n }\n\n // Dashboard process was killed externally — reset flag and fall through to restart\n console.error('[memorix] Dashboard process no longer running, restarting...');\n dashboardRunning = false;\n }\n\n try {\n const pathMod = await import('node:path');\n const fsMod = await import('node:fs');\n const { fileURLToPath } = await import('node:url');\n const { startDashboard } = await import('./dashboard/server.js');\n\n // Try multiple strategies to find the static files directory\n // When running from CLI (dist/cli/index.js), __dirname = dist/cli/, need to go up\n const candidates = [\n pathMod.default.join(__dirname, '..', 'dashboard', 'static'),\n pathMod.default.join(__dirname, 'dashboard', 'static'),\n pathMod.default.join(pathMod.default.dirname(fileURLToPath(import.meta.url)), '..', 'dashboard', 'static'),\n pathMod.default.join(pathMod.default.dirname(fileURLToPath(import.meta.url)), 'dashboard', 'static'),\n ];\n\n // Log all candidates for debugging\n for (const [i, c] of candidates.entries()) {\n const hasIndex = fsMod.existsSync(pathMod.default.join(c, 'index.html'));\n console.error(`[memorix] candidate[${i}]: ${c} (has index.html: ${hasIndex})`);\n }\n\n let staticDir = candidates[0];\n for (const c of candidates) {\n if (fsMod.existsSync(pathMod.default.join(c, 'index.html'))) {\n staticDir = c;\n break;\n }\n }\n console.error(`[memorix] Dashboard staticDir: ${staticDir}`);\n\n // Start in background (non-blocking), disable auto-open (we'll open it ourselves)\n startDashboard(projectDir, portNum, staticDir, project.id, project.name, false, {\n registry: teamRegistry,\n fileLocks,\n taskManager,\n messageBus,\n })\n .then(() => { dashboardRunning = true; })\n .catch((err) => { console.error('[memorix] Dashboard error:', err); dashboardRunning = false; });\n\n // Poll until the server is actually listening (up to 5s)\n const { createConnection } = await import('node:net');\n await new Promise<void>(resolve => {\n const deadline = Date.now() + 5000;\n const tryConnect = () => {\n const sock = createConnection(portNum, '127.0.0.1');\n sock.once('connect', () => { sock.destroy(); resolve(); });\n sock.once('error', () => {\n sock.destroy();\n if (Date.now() < deadline) setTimeout(tryConnect, 100);\n else resolve(); // give up, return anyway\n });\n };\n tryConnect();\n });\n dashboardRunning = true;\n\n // Open browser from MCP side\n const { exec: execCmd } = await import('node:child_process');\n const openCmd =\n process.platform === 'win32' ? `start \"\" \"${url}\"` :\n process.platform === 'darwin' ? `open \"${url}\"` :\n `xdg-open \"${url}\"`;\n execCmd(openCmd, () => { });\n\n return {\n content: [{\n type: 'text' as const,\n text: [\n `Memorix Dashboard started!`,\n ``,\n `URL: ${url}`,\n `Project: ${project.name} (${project.id})`,\n `Static: ${staticDir}`,\n ``,\n `The dashboard has been opened in your default browser.`,\n `It shows your knowledge graph, observations, retention scores, and project stats.`,\n ].join('\\n'),\n }],\n };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: `Failed to start dashboard: ${err instanceof Error ? err.message : String(err)}` }],\n };\n }\n },\n );\n\n // ================================================================\n // Team Collaboration Tools (Multi-Agent)\n // ================================================================\n\n const { AgentRegistry } = await import('./team/registry.js');\n const { MessageBus } = await import('./team/messages.js');\n const { FileLockRegistry } = await import('./team/file-locks.js');\n const { TaskManager } = await import('./team/tasks.js');\n\n // Use shared instances (from HTTP server) or create new ones (stdio mode)\n const teamRegistry = sharedTeam?.registry ?? new AgentRegistry();\n const messageBus = sharedTeam?.messageBus ?? new MessageBus(teamRegistry);\n const fileLocks = sharedTeam?.fileLocks ?? new FileLockRegistry();\n const taskManager = sharedTeam?.taskManager ?? new TaskManager();\n\n // File-based persistence for cross-IDE team state sharing (stdio mode only).\n // In HTTP mode, all sessions share in-memory state — no persistence needed.\n let teamPersist: import('./team/persistence.js').TeamPersistence | null = null;\n if (!sharedTeam) {\n const { TeamPersistence } = await import('./team/persistence.js');\n const { join } = await import('node:path');\n teamPersist = new TeamPersistence(\n join(projectDir, 'team-state.json'),\n teamRegistry, messageBus, taskManager, fileLocks,\n );\n await teamPersist.sync();\n }\n const teamSync = () => teamPersist ? teamPersist.sync() : Promise.resolve();\n const teamFlush = () => teamPersist ? teamPersist.flush() : Promise.resolve();\n\n // ── team_manage (join / leave / status) ─────────────────────────\n server.registerTool(\n 'team_manage',\n {\n title: 'Team Management',\n description:\n 'Register, unregister, or list agents in the team. ' +\n 'Action \"join\": register this agent (returns agent ID). ' +\n 'Action \"leave\": mark agent inactive, release locks. ' +\n 'Action \"status\": list all agents with roles and capabilities.',\n inputSchema: {\n action: z.enum(['join', 'leave', 'status']).describe('Operation to perform'),\n name: z.string().optional().describe('Agent name for join (e.g., \"cursor-frontend\")'),\n role: z.string().optional().describe('Agent role for join'),\n capabilities: z.array(z.string()).optional().describe('Agent capabilities for join'),\n agentId: z.string().optional().describe('Agent ID for leave'),\n },\n },\n async ({ action, name, role, capabilities, agentId }) => {\n await teamSync();\n if (action === 'join') {\n const trimmed = (name || '').trim();\n if (!trimmed) return { content: [{ type: 'text' as const, text: '❌ Agent name is required' }], isError: true };\n if (trimmed.length > 100) return { content: [{ type: 'text' as const, text: '❌ Agent name too long (max 100 chars)' }], isError: true };\n const agent = teamRegistry.join({ name: trimmed, role, capabilities: capabilities ? coerceStringArray(capabilities) : undefined });\n await teamFlush();\n return {\n content: [{\n type: 'text' as const,\n text: `✅ Joined team as \"${agent.name}\" (ID: ${agent.id})\\nRole: ${agent.role ?? 'unspecified'}\\nActive agents: ${teamRegistry.getActiveCount()}`,\n }],\n };\n }\n if (action === 'leave') {\n if (!agentId) return { content: [{ type: 'text' as const, text: '❌ agentId is required for leave' }], isError: true };\n const left = teamRegistry.leave(agentId);\n if (!left) return { content: [{ type: 'text' as const, text: '⚠️ Agent not found' }] };\n const releasedLocks = fileLocks.releaseAll(agentId);\n messageBus.clearInbox(agentId);\n await teamFlush();\n const parts: string[] = [];\n if (releasedLocks > 0) parts.push(`released ${releasedLocks} lock(s)`);\n return {\n content: [{\n type: 'text' as const,\n text: `Left team.${parts.length > 0 ? ' ' + parts.join(', ') + '.' : ''}\\nActive agents: ${teamRegistry.getActiveCount()}`,\n }],\n };\n }\n // status\n const agents = teamRegistry.listAgents();\n if (agents.length === 0) {\n return { content: [{ type: 'text' as const, text: 'No agents registered. Use action \"join\" to register.' }] };\n }\n const lines = agents.map(a =>\n `${a.status === 'active' ? '●' : '○'} ${a.name} (${a.id}) — ${a.role ?? 'no role'} [${a.capabilities.join(', ') || '-'}]`,\n );\n return {\n content: [{\n type: 'text' as const,\n text: `Team: ${teamRegistry.getActiveCount()} active / ${agents.length} total\\n\\n${lines.join('\\n')}`,\n }],\n };\n },\n );\n\n // ── team_file_lock (lock / unlock / status) ───────────────────\n server.registerTool(\n 'team_file_lock',\n {\n title: 'File Lock Management',\n description:\n 'Advisory file locks to prevent conflicting edits. Auto-releases after 10 min TTL. ' +\n 'Action \"lock\": acquire lock. Action \"unlock\": release lock. Action \"status\": check lock status.',\n inputSchema: {\n action: z.enum(['lock', 'unlock', 'status']).describe('Operation to perform'),\n file: z.string().optional().describe('File path (required for lock/unlock, optional for status — omit to list all)'),\n agentId: z.string().optional().describe('Agent ID (required for lock/unlock)'),\n },\n },\n async ({ action, file, agentId }) => {\n await teamSync();\n fileLocks.cleanExpired();\n if (action === 'lock') {\n if (!file || !agentId) return { content: [{ type: 'text' as const, text: '❌ file and agentId are required for lock' }], isError: true };\n const agent = teamRegistry.getAgent(agentId);\n if (!agent || agent.status !== 'active') {\n return { content: [{ type: 'text' as const, text: `❌ Unknown or inactive agent: ${agentId.slice(0, 8)}…` }], isError: true };\n }\n const result = fileLocks.lock(file, agentId);\n await teamFlush();\n if (result.success) return { content: [{ type: 'text' as const, text: `Locked: ${file}` }] };\n const owner = teamRegistry.getAgent(result.lockedBy);\n return { content: [{ type: 'text' as const, text: `Denied — locked by ${owner?.name ?? result.lockedBy.slice(0, 8)}` }], isError: true };\n }\n if (action === 'unlock') {\n if (!file || !agentId) return { content: [{ type: 'text' as const, text: '❌ file and agentId are required for unlock' }], isError: true };\n const released = fileLocks.unlock(file, agentId);\n await teamFlush();\n return { content: [{ type: 'text' as const, text: released ? `Unlocked: ${file}` : `Cannot unlock: not owner or not locked` }] };\n }\n // status\n if (file) {\n const status = fileLocks.getStatus(file);\n if (!status) return { content: [{ type: 'text' as const, text: `${file} — unlocked` }] };\n const owner = teamRegistry.getAgent(status.lockedBy);\n return { content: [{ type: 'text' as const, text: `${file} — locked by ${owner?.name ?? status.lockedBy.slice(0, 8)} (expires ${status.expiresAt.toISOString()})` }] };\n }\n const all = fileLocks.listLocks();\n if (all.length === 0) return { content: [{ type: 'text' as const, text: 'No files locked' }] };\n const lines = all.map(l => {\n const owner = teamRegistry.getAgent(l.lockedBy);\n return `${l.file} — ${owner?.name ?? l.lockedBy.slice(0, 8)}`;\n });\n return { content: [{ type: 'text' as const, text: `Locked files (${all.length}):\\n${lines.join('\\n')}` }] };\n },\n );\n\n // ── team_task (create / claim / complete / list) ──────────────\n server.registerTool(\n 'team_task',\n {\n title: 'Task Board',\n description:\n 'Create, claim, complete, or list tasks in the team task board. Supports dependencies. ' +\n 'Action \"create\": create a task. Action \"claim\": assign to yourself. ' +\n 'Action \"complete\": mark done with result. Action \"list\": show tasks.',\n inputSchema: {\n action: z.enum(['create', 'claim', 'complete', 'list']).describe('Operation to perform'),\n description: z.string().optional().describe('Task description (for create)'),\n deps: z.array(z.string()).optional().describe('Dependency task IDs (for create)'),\n taskId: z.string().optional().describe('Task ID (for claim/complete)'),\n agentId: z.string().optional().describe('Agent ID (for claim/complete)'),\n result: z.string().optional().describe('Result summary (for complete)'),\n status: z.enum(['pending', 'in_progress', 'completed', 'failed']).optional().describe('Filter by status (for list)'),\n available: z.boolean().optional().describe('Show only claimable tasks (for list)'),\n },\n },\n async ({ action, description: desc, deps, taskId, agentId, result, status, available }) => {\n await teamSync();\n try {\n if (action === 'create') {\n if (!desc) return { content: [{ type: 'text' as const, text: '❌ description is required for create' }], isError: true };\n const task = taskManager.create({ description: desc, deps: deps ? coerceStringArray(deps) : undefined });\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Task created: ${task.id} \"${desc}\"${task.deps.length > 0 ? ` (depends on ${task.deps.length})` : ''}` }] };\n }\n if (action === 'claim') {\n if (!taskId || !agentId) return { content: [{ type: 'text' as const, text: '❌ taskId and agentId required for claim' }], isError: true };\n const agent = teamRegistry.getAgent(agentId);\n if (!agent || agent.status !== 'active') return { content: [{ type: 'text' as const, text: `❌ Unknown or inactive agent` }], isError: true };\n const task = taskManager.claim(taskId, agentId);\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Task claimed by ${agent.name}: \"${task.description}\"` }] };\n }\n if (action === 'complete') {\n if (!taskId || !agentId || !result) return { content: [{ type: 'text' as const, text: '❌ taskId, agentId, and result required for complete' }], isError: true };\n const existingTask = taskManager.getTask(taskId);\n const allowRescue = existingTask?.assignee ? teamRegistry.getAgent(existingTask.assignee)?.status !== 'active' : false;\n const task = taskManager.complete(taskId, agentId, result, allowRescue);\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Task completed${allowRescue ? ' (rescued)' : ''}: \"${task.description}\"\\nResult: ${result}` }] };\n }\n // list\n const list = available ? taskManager.getAvailable() : taskManager.list(status ? { status } : undefined);\n if (list.length === 0) return { content: [{ type: 'text' as const, text: available ? 'No tasks available to claim' : 'No tasks found' }] };\n const statusIcon: Record<string, string> = { pending: '[ ]', in_progress: '[~]', completed: '[x]', failed: '[!]' };\n const lines = list.map(t => {\n const assignee = t.assignee ? teamRegistry.getAgent(t.assignee)?.name ?? t.assignee.slice(0, 8) : 'unassigned';\n return `${statusIcon[t.status] ?? '[ ]'} ${t.id} \"${t.description}\" — ${assignee}${t.deps.length > 0 ? ` [deps: ${t.deps.length}]` : ''}`;\n });\n return { content: [{ type: 'text' as const, text: `Tasks (${list.length}):\\n${lines.join('\\n')}` }] };\n } catch (err) {\n return { content: [{ type: 'text' as const, text: `❌ ${(err as Error).message}` }], isError: true };\n }\n },\n );\n\n // ── team_message (send / broadcast / inbox) ───────────────────\n server.registerTool(\n 'team_message',\n {\n title: 'Team Messaging',\n description:\n 'Send, broadcast, or read messages between agents. ' +\n 'Action \"send\": direct message to one agent. Action \"broadcast\": message all active agents. ' +\n 'Action \"inbox\": read this agent\\'s inbox.',\n inputSchema: {\n action: z.enum(['send', 'broadcast', 'inbox']).describe('Operation to perform'),\n from: z.string().optional().describe('Sender agent ID (for send/broadcast)'),\n to: z.string().optional().describe('Receiver agent ID (for send)'),\n type: z.enum(['request', 'response', 'info', 'announcement', 'contract', 'error']).optional().describe('Message type (for send/broadcast)'),\n content: z.string().optional().describe('Message content (for send/broadcast)'),\n agentId: z.string().optional().describe('Agent ID (for inbox)'),\n markRead: z.boolean().optional().default(false).describe('Mark messages as read (for inbox)'),\n },\n },\n async ({ action, from, to, type: msgType, content, agentId, markRead }) => {\n await teamSync();\n if (action === 'send') {\n if (!from || !to || !msgType || !content) return { content: [{ type: 'text' as const, text: '❌ from, to, type, and content required for send' }], isError: true };\n if (content.length > 10_000) return { content: [{ type: 'text' as const, text: '❌ Message too large (max 10KB)' }], isError: true };\n try {\n const msg = messageBus.send({ from, to, type: msgType, content });\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Message sent (${msgType}) to ${to.slice(0, 8)}… | ID: ${msg.id.slice(0, 8)}…` }] };\n } catch (err) {\n return { content: [{ type: 'text' as const, text: `❌ ${(err as Error).message}` }], isError: true };\n }\n }\n if (action === 'broadcast') {\n if (!from || !msgType || !content) return { content: [{ type: 'text' as const, text: '❌ from, type, and content required for broadcast' }], isError: true };\n if (content.length > 10_000) return { content: [{ type: 'text' as const, text: '❌ Message too large (max 10KB)' }], isError: true };\n const msgs = messageBus.broadcast({ from, type: msgType, content });\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Broadcast (${msgType}) to ${msgs.length} agent(s)` }] };\n }\n // inbox\n const inboxId = agentId || from || '';\n if (!inboxId) return { content: [{ type: 'text' as const, text: '❌ agentId required for inbox' }], isError: true };\n const inbox = messageBus.getInbox(inboxId);\n const unread = messageBus.getUnreadCount(inboxId);\n if (inbox.length === 0) return { content: [{ type: 'text' as const, text: 'Inbox empty' }] };\n if (markRead) {\n messageBus.markRead(inboxId, inbox.map(m => m.id));\n await teamFlush();\n }\n const lines = inbox.slice(-10).map(m => {\n const sender = teamRegistry.getAgent(m.from);\n return `${m.read ? ' ' : '*'} [${m.type}] from ${sender?.name ?? m.from.slice(0, 8)}: ${m.content.slice(0, 100)}`;\n });\n return { content: [{ type: 'text' as const, text: `Inbox: ${unread} unread / ${inbox.length} total\\n\\n${lines.join('\\n')}` }] };\n },\n );\n\n // Deferred initialization — runs AFTER transport connect so MCP handshake isn't blocked.\n // Hooks auto-install, sync advisory scan, and file watcher are non-essential for tool\n // functionality and can take 30-60s on machines with many IDEs/projects.\n const deferredInit = async () => {\n // Auto-install hooks for newly detected agents\n // Respects ~/.memorix/settings.json { \"autoInstallHooks\": false } to skip\n try {\n let autoInstall = true;\n try {\n const { homedir } = await import('node:os');\n const { join } = await import('node:path');\n const { readFile } = await import('node:fs/promises');\n const settingsPath = join(homedir(), '.memorix', 'settings.json');\n const raw = await readFile(settingsPath, 'utf-8');\n const settings = JSON.parse(raw);\n if (settings.autoInstallHooks === false) {\n autoInstall = false;\n console.error('[memorix] autoInstallHooks disabled in ~/.memorix/settings.json — skipping hook auto-install');\n }\n } catch { /* no settings file or parse error — default to auto-install */ }\n\n if (autoInstall) {\n const { getHookStatus, installHooks, detectInstalledAgents } = await import('./hooks/installers/index.js');\n const { join } = await import('node:path');\n const { access } = await import('node:fs/promises');\n const workDir = cwd ?? process.cwd();\n const statuses = await getHookStatus(workDir);\n const installedAgents = new Set(statuses.filter((s) => s.installed).map((s) => s.agent));\n const detectedAgents = await detectInstalledAgents();\n\n // Map agent → project-level marker directory that the IDE creates on its own.\n // Only auto-install hooks if this directory already exists in the project,\n // preventing creation of unwanted IDE config dirs (e.g. .windsurf/ in a Cursor project).\n const AGENT_MARKER_DIR: Record<string, string> = {\n claude: '.claude',\n windsurf: '.windsurf',\n cursor: '.cursor',\n copilot: '.vscode',\n opencode: '.opencode',\n kiro: '.kiro',\n antigravity: '.gemini',\n trae: '.trae',\n };\n\n for (const agent of detectedAgents) {\n if (installedAgents.has(agent)) continue;\n // Skip if the IDE's marker directory doesn't exist in this project\n const markerDir = AGENT_MARKER_DIR[agent];\n if (markerDir) {\n try { await access(join(workDir, markerDir)); } catch { continue; }\n }\n try {\n const config = await installHooks(agent, workDir);\n console.error(`[memorix] Auto-installed hooks for ${agent} → ${config.configPath}`);\n } catch { /* skip */ }\n }\n }\n } catch { /* hooks install is optional */ }\n\n // Sync advisory: compute once, show on first memorix_search\n try {\n const engine = new WorkspaceSyncEngine(project.rootPath);\n const scan = await engine.scan();\n const lines: string[] = [];\n\n const totalMCP = Object.values(scan.mcpConfigs).reduce((sum, arr) => sum + arr.length, 0);\n const totalSkills = scan.skills.length;\n const totalRules = scan.rulesCount;\n const totalWorkflows = scan.workflows.length;\n\n if (totalMCP > 0 || totalSkills > 0 || totalRules > 0 || totalWorkflows > 0) {\n lines.push('', '---', '🔄 **Cross-Agent Sync Available**');\n for (const [agent, servers] of Object.entries(scan.mcpConfigs)) {\n const list = servers as MCPServerEntry[];\n if (list.length > 0) {\n lines.push(`- **${agent}** MCP: ${list.map(s => s.name).join(', ')}`);\n }\n }\n if (totalSkills > 0) {\n const byAgent = new Map<string, string[]>();\n for (const sk of scan.skills) {\n const arr = byAgent.get(sk.sourceAgent) || [];\n arr.push(sk.name);\n byAgent.set(sk.sourceAgent, arr);\n }\n for (const [agent, names] of byAgent) {\n lines.push(`- **${agent}** skills: ${names.join(', ')}`);\n }\n }\n if (scan.skillConflicts.length > 0) lines.push(` ⚠️ ${scan.skillConflicts.length} name conflict(s)`);\n if (totalRules > 0) lines.push(`- **${totalRules} rule(s)** found`);\n if (totalWorkflows > 0) lines.push(`- **${totalWorkflows} workflow(s)** found`);\n lines.push('');\n lines.push('⚠️ IMPORTANT INSTRUCTIONS FOR AI AGENT:');\n lines.push('1. Tell the user what configs/skills are available from other agents (list them).');\n lines.push('2. Ask which ones they want to sync.');\n lines.push('3. DO NOT manually copy files or run shell commands to sync.');\n lines.push('4. ONLY use `memorix_workspace_sync action=\"apply\" target=\"<agent>\"` to sync all,');\n lines.push(' or add `items=[\"name1\",\"name2\"]` to sync specific items selectively.');\n syncAdvisory = lines.join('\\n');\n }\n console.error(`[memorix] Sync advisory: ${syncAdvisory ? 'available' : 'nothing to sync'}`);\n } catch { /* sync scan is optional */ }\n\n // ── Background retention cleanup ────────────────────────────────\n // Archive expired memories automatically so users never need to run it manually.\n try {\n const { archiveExpired } = await import('./memory/retention.js');\n const archiveResult = await archiveExpired(projectDir);\n if (archiveResult.archived > 0) {\n console.error(`[memorix] Auto-archived ${archiveResult.archived} expired observation(s)`);\n }\n } catch { /* retention cleanup is optional */ }\n\n // ── Background consolidation ─────────────────────────────────────\n // With LLM: semantic dedup (higher quality). Without: Jaccard similarity.\n // Users who configure an API key want quality — each call is only ~500 tokens.\n try {\n if (isLLMEnabled()) {\n const { getAllObservations, resolveObservations } = await import('./memory/observations.js');\n const { deduplicateMemory } = await import('./llm/memory-manager.js');\n const allObs = getAllObservations().filter(o => (o.status ?? 'active') === 'active' && o.projectId === project.id);\n if (allObs.length > 10) {\n const grouped = new Map<string, typeof allObs>();\n for (const obs of allObs) {\n const key = `${obs.entityName}::${obs.type}`;\n if (!grouped.has(key)) grouped.set(key, []);\n grouped.get(key)!.push(obs);\n }\n const toResolve: number[] = [];\n for (const [, group] of grouped) {\n if (group.length < 2) continue;\n group.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());\n for (let i = 0; i < group.length - 1 && i < 5; i++) {\n try {\n const older = group[i], newer = group[i + 1];\n const decision = await deduplicateMemory(\n { title: newer.title, narrative: newer.narrative, facts: newer.facts },\n [{ id: older.id, title: older.title, narrative: older.narrative, facts: older.facts.join('\\n') }],\n );\n if (decision && (decision.action === 'UPDATE' || decision.action === 'NONE')) {\n toResolve.push(decision.action === 'UPDATE' ? older.id : newer.id);\n } else if (decision?.action === 'DELETE' && decision.targetId) {\n toResolve.push(decision.targetId);\n }\n } catch { /* skip individual comparison errors */ }\n }\n }\n if (toResolve.length > 0) {\n await resolveObservations([...new Set(toResolve)], 'resolved');\n console.error(`[memorix] Auto-dedup (LLM): resolved ${toResolve.length} redundant observation(s)`);\n }\n }\n } else {\n const { executeConsolidation } = await import('./memory/consolidation.js');\n const result = await executeConsolidation(projectDir, project.id, { threshold: 0.55 });\n if (result.observationsMerged > 0) {\n console.error(`[memorix] Auto-consolidated: merged ${result.observationsMerged} duplicate(s) across ${result.clustersFound} cluster(s)`);\n }\n }\n } catch { /* consolidation is optional */ }\n\n // Watch for external writes (e.g., from hook processes) and hot-reload.\n // Uses watchFile (polling) instead of watch because atomicWriteFile uses\n // rename(), which changes the file inode — fs.watch loses track on Windows.\n const observationsFile = projectDir + '/observations.json';\n let reloadDebounce: ReturnType<typeof setTimeout> | null = null;\n let reloading = false; // guard: skip if a reload is already in progress\n // lastInternalWriteMs + markInternalWrite are module-level (see top of file)\n try {\n watchFile(observationsFile, { interval: 5000 }, (curr, prev) => {\n if (curr.mtimeMs === prev.mtimeMs) return; // no actual change\n // Skip reload if a MCP tool wrote recently — data is already in memory\n if (Date.now() - lastInternalWriteMs < 10_000) return;\n if (reloading) return; // skip — previous reload still running\n if (reloadDebounce) clearTimeout(reloadDebounce);\n reloadDebounce = setTimeout(async () => {\n if (reloading) return;\n reloading = true;\n try {\n await resetDb();\n await initObservations(projectDir);\n const count = await reindexObservations();\n if (count > 0) {\n console.error(`[memorix] Hot-reloaded ${count} observations (external write detected)`);\n }\n } catch { /* silent */ }\n reloading = false;\n }, 3000);\n });\n console.error(`[memorix] Watching for external writes (hooks hot-reload enabled)`);\n } catch {\n console.error(`[memorix] Warning: could not watch observations file for hot-reload`);\n }\n };\n\n return { server, graphManager, projectId: project.id, deferredInit };\n}\n","/**\n * Knowledge Graph Manager\n *\n * Manages the Entity-Relation knowledge graph.\n * Source: MCP Official Memory Server v0.6.3 (complete rewrite with same API).\n *\n * Key differences from official implementation:\n * - Uses per-project JSONL files (official uses single file)\n * - Async initialization with persistence layer\n * - Project-scoped operations\n */\n\nimport type { Entity, Relation, KnowledgeGraph } from '../types.js';\nimport { saveGraphJsonl, loadGraphJsonl } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\nexport class KnowledgeGraphManager {\n private entities: Entity[] = [];\n private relations: Relation[] = [];\n private projectDir: string;\n private initialized = false;\n /** Index: lowercase entity name → Entity for O(1) lookups */\n private entityIndex = new Map<string, Entity>();\n\n constructor(projectDir: string) {\n this.projectDir = projectDir;\n }\n\n /** Rebuild the entity name index */\n private rebuildIndex(): void {\n this.entityIndex.clear();\n for (const e of this.entities) {\n this.entityIndex.set(e.name.toLowerCase(), e);\n }\n }\n\n /** Load graph from disk on first access */\n async init(): Promise<void> {\n if (this.initialized) return;\n const data = await loadGraphJsonl(this.projectDir);\n this.entities = data.entities;\n this.relations = data.relations;\n this.rebuildIndex();\n this.initialized = true;\n }\n\n /** Find entity by name (case-insensitive, O(1)) */\n findEntityByName(name: string): Entity | undefined {\n return this.entityIndex.get(name.toLowerCase());\n }\n\n /** Get all entity names as a Set (lowercase, for fast membership checks) */\n getEntityNameSet(): Set<string> {\n return new Set(this.entityIndex.keys());\n }\n\n /** Persist current state to disk with file lock (cross-process safe) */\n private async save(): Promise<void> {\n await withFileLock(this.projectDir, async () => {\n await saveGraphJsonl(this.projectDir, this.entities, this.relations);\n });\n }\n\n /** Create new entities (skip duplicates by name) */\n async createEntities(entities: Entity[]): Promise<Entity[]> {\n await this.init();\n const newEntities = entities.filter(\n (e) => !this.entityIndex.has(e.name.toLowerCase()),\n );\n this.entities.push(...newEntities);\n if (newEntities.length > 0) this.rebuildIndex();\n await this.save();\n return newEntities;\n }\n\n /** Create new relations (skip duplicates) */\n async createRelations(relations: Relation[]): Promise<Relation[]> {\n await this.init();\n const newRelations = relations.filter(\n (r) =>\n !this.relations.some(\n (existing) =>\n existing.from === r.from &&\n existing.to === r.to &&\n existing.relationType === r.relationType,\n ),\n );\n this.relations.push(...newRelations);\n await this.save();\n return newRelations;\n }\n\n /** Add observations to existing entities */\n async addObservations(\n observations: { entityName: string; contents: string[] }[],\n ): Promise<{ entityName: string; addedObservations: string[] }[]> {\n await this.init();\n const results = observations.map((o) => {\n const entity = this.entities.find((e) => e.name === o.entityName);\n if (!entity) {\n throw new Error(`Entity with name ${o.entityName} not found`);\n }\n const newObs = o.contents.filter((c) => !entity.observations.includes(c));\n entity.observations.push(...newObs);\n return { entityName: o.entityName, addedObservations: newObs };\n });\n await this.save();\n return results;\n }\n\n /** Delete entities and their associated relations */\n async deleteEntities(entityNames: string[]): Promise<void> {\n await this.init();\n this.entities = this.entities.filter((e) => !entityNames.includes(e.name));\n this.relations = this.relations.filter(\n (r) => !entityNames.includes(r.from) && !entityNames.includes(r.to),\n );\n this.rebuildIndex();\n await this.save();\n }\n\n /** Delete specific observations from entities */\n async deleteObservations(\n deletions: { entityName: string; observations: string[] }[],\n ): Promise<void> {\n await this.init();\n for (const d of deletions) {\n const entity = this.entities.find((e) => e.name === d.entityName);\n if (entity) {\n entity.observations = entity.observations.filter(\n (o) => !d.observations.includes(o),\n );\n }\n }\n await this.save();\n }\n\n /** Delete specific relations */\n async deleteRelations(relations: Relation[]): Promise<void> {\n await this.init();\n this.relations = this.relations.filter(\n (r) =>\n !relations.some(\n (del) =>\n r.from === del.from &&\n r.to === del.to &&\n r.relationType === del.relationType,\n ),\n );\n await this.save();\n }\n\n /** Read the entire graph */\n async readGraph(): Promise<KnowledgeGraph> {\n await this.init();\n return { entities: this.entities, relations: this.relations };\n }\n\n /** Search nodes by query string (upgraded from official's basic includes) */\n async searchNodes(query: string): Promise<KnowledgeGraph> {\n await this.init();\n const lowerQuery = query.toLowerCase();\n\n const filteredEntities = this.entities.filter(\n (e) =>\n e.name.toLowerCase().includes(lowerQuery) ||\n e.entityType.toLowerCase().includes(lowerQuery) ||\n e.observations.some((o) => o.toLowerCase().includes(lowerQuery)),\n );\n\n const filteredNames = new Set(filteredEntities.map((e) => e.name));\n\n const filteredRelations = this.relations.filter(\n (r) => filteredNames.has(r.from) && filteredNames.has(r.to),\n );\n\n return { entities: filteredEntities, relations: filteredRelations };\n }\n\n /** Open specific nodes by name */\n async openNodes(names: string[]): Promise<KnowledgeGraph> {\n await this.init();\n\n const filteredEntities = this.entities.filter((e) => names.includes(e.name));\n const filteredNames = new Set(filteredEntities.map((e) => e.name));\n\n const filteredRelations = this.relations.filter(\n (r) => filteredNames.has(r.from) && filteredNames.has(r.to),\n );\n\n return { entities: filteredEntities, relations: filteredRelations };\n }\n}\n","/**\n * Auto-Relation Creator\n *\n * Automatically creates Knowledge Graph relations from entity extraction.\n * Inspired by mcp-memory-service's typed relationships and MemCP's MAGMA 4-graph.\n *\n * When an observation is stored:\n * 1. Extract entities from narrative (files, modules, CamelCase)\n * 2. Find matching existing entities in the graph\n * 3. Auto-create relations: \"references\", \"modifies\", or \"causes\" (if causal)\n *\n * This is \"implicit memory\" — the agent doesn't need to call create_relations.\n */\n\nimport type { Observation, Relation } from '../types.js';\nimport type { KnowledgeGraphManager } from './graph.js';\nimport type { ExtractedEntities } from './entity-extractor.js';\n\n/**\n * Infer relation type based on observation type and causal language.\n */\nfunction inferRelationType(obs: Observation): string {\n if (obs.hasCausalLanguage) return 'causes';\n\n switch (obs.type) {\n case 'problem-solution':\n return 'fixes';\n case 'decision':\n case 'trade-off':\n return 'decides';\n case 'what-changed':\n return 'modifies';\n case 'gotcha':\n return 'warns_about';\n default:\n return 'references';\n }\n}\n\n/**\n * Auto-create relations from a stored observation.\n *\n * Scans the knowledge graph for entities matching extracted file names,\n * modules, and identifiers, then creates typed relations.\n *\n * Returns the number of relations created.\n */\nexport async function createAutoRelations(\n obs: Observation,\n extracted: ExtractedEntities,\n graphManager: KnowledgeGraphManager,\n): Promise<number> {\n const relationType = inferRelationType(obs);\n const relations: Relation[] = [];\n\n // Skip self-references\n const selfName = obs.entityName.toLowerCase();\n\n // Check extracted identifiers against existing entities (O(1) lookups via index)\n const candidates = [\n ...extracted.identifiers,\n ...extracted.files.map((f) => f.split('/').pop()?.replace(/\\.\\w+$/, '') ?? ''),\n ...extracted.modules.map((m) => m.split(/[./]/).pop() ?? ''),\n ].filter((c) => c.length >= 3);\n\n for (const candidate of candidates) {\n const lower = candidate.toLowerCase();\n if (lower === selfName) continue;\n\n const matchedEntity = graphManager.findEntityByName(candidate);\n if (matchedEntity) {\n relations.push({\n from: obs.entityName,\n to: matchedEntity.name,\n relationType,\n });\n }\n }\n\n // Also create relations from explicit filesModified → existing entities\n for (const file of obs.filesModified) {\n const basename = file.split('/').pop()?.replace(/\\.\\w+$/, '') ?? '';\n if (basename.length < 3 || basename.toLowerCase() === selfName) continue;\n\n const matchedEntity = graphManager.findEntityByName(basename);\n if (matchedEntity) {\n relations.push({\n from: obs.entityName,\n to: matchedEntity.name,\n relationType: 'modifies',\n });\n }\n }\n\n if (relations.length === 0) return 0;\n\n // Deduplicate\n const unique = relations.filter(\n (r, i, arr) =>\n arr.findIndex(\n (o) => o.from === r.from && o.to === r.to && o.relationType === r.relationType,\n ) === i,\n );\n\n const created = await graphManager.createRelations(unique);\n return created.length;\n}\n","/**\n * Compact Engine\n *\n * Orchestrates the 3-layer Progressive Disclosure workflow.\n * Source: claude-mem's proven architecture (27K stars, ~10x token savings).\n *\n * Layer 1 (search) → Compact index with IDs (~50-100 tokens/result)\n * Layer 2 (timeline) → Chronological context around an observation\n * Layer 3 (detail) → Full observation content (~500-1000 tokens/result)\n */\n\nimport type { SearchOptions, IndexEntry, TimelineContext, MemorixDocument } from '../types.js';\nimport { searchObservations, getTimeline } from '../store/orama-store.js';\nimport { getObservation } from '../memory/observations.js';\nimport { formatIndexTable, formatTimeline, formatObservationDetail } from './index-format.js';\nimport { countTextTokens } from './token-budget.js';\n\n/**\n * Layer 1: Search and return a compact index.\n * Agent scans this to decide which observations to fetch in detail.\n */\nexport async function compactSearch(options: SearchOptions): Promise<{\n entries: IndexEntry[];\n formatted: string;\n totalTokens: number;\n}> {\n const entries = await searchObservations(options);\n const formatted = formatIndexTable(entries, options.query);\n const totalTokens = countTextTokens(formatted);\n\n return { entries, formatted, totalTokens };\n}\n\n/**\n * Layer 2: Get timeline context around an anchor observation.\n * Shows what happened before and after for temporal understanding.\n */\nexport async function compactTimeline(\n anchorId: number,\n projectId?: string,\n depthBefore = 3,\n depthAfter = 3,\n): Promise<{\n timeline: TimelineContext;\n formatted: string;\n totalTokens: number;\n}> {\n const result = await getTimeline(anchorId, projectId, depthBefore, depthAfter);\n\n const timeline: TimelineContext = {\n anchorId,\n anchorEntry: result.anchor,\n before: result.before,\n after: result.after,\n };\n\n const formatted = formatTimeline(timeline);\n const totalTokens = countTextTokens(formatted);\n\n return { timeline, formatted, totalTokens };\n}\n\n/**\n * Layer 3: Get full observation details by IDs.\n * Only called after the agent has filtered via L1/L2.\n */\nexport async function compactDetail(\n ids: number[],\n): Promise<{\n documents: MemorixDocument[];\n formatted: string;\n totalTokens: number;\n}> {\n // Use in-memory observations for reliable ID lookup (Orama where-clause\n // can be unreliable with empty term + number filter)\n const documents: MemorixDocument[] = [];\n for (const id of ids) {\n const obs = getObservation(id);\n if (obs) {\n documents.push({\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n });\n }\n }\n\n const formattedParts = documents.map((doc: MemorixDocument) =>\n formatObservationDetail(doc),\n );\n\n const formatted = formattedParts.join('\\n\\n' + '═'.repeat(50) + '\\n\\n');\n const totalTokens = countTextTokens(formatted);\n\n return { documents, formatted, totalTokens };\n}\n","/**\n * Index Formatter\n *\n * Formats observation search results into the compact index table format.\n * Source: claude-mem's Progressive Disclosure index format.\n *\n * Output is a markdown table that agents can scan efficiently:\n * | ID | Time | T | Title | Tokens |\n * |-------|----------|----|--------------------------|--------|\n * | #42 | 2:14 PM | 🔴 | port 3001 conflict fix | ~155 |\n */\n\nimport type { IndexEntry, TimelineContext } from '../types.js';\n\n/**\n * Format a list of IndexEntries as a compact markdown table.\n * Grouped by date for readability (claude-mem pattern).\n */\nexport function formatIndexTable(entries: IndexEntry[], query?: string): string {\n if (entries.length === 0) {\n return query\n ? `No observations found matching \"${query}\".`\n : 'No observations found.';\n }\n\n const lines: string[] = [];\n\n if (query) {\n lines.push(`Found ${entries.length} observation(s) matching \"${query}\":\\n`);\n }\n\n lines.push('| ID | Time | T | Title | Tokens |');\n lines.push('|----|------|---|-------|--------|');\n\n // Check if any entry has matchedFields (explainable recall)\n const hasExplanation = entries.some(e => (e as unknown as Record<string, unknown>)['matchedFields']);\n\n if (hasExplanation) {\n lines.pop(); // remove previous header\n lines.pop();\n lines.push('| ID | Time | T | Title | Tokens | Matched |');\n lines.push('|----|------|---|-------|--------|---------|');\n }\n\n for (const entry of entries) {\n const matched = (entry as unknown as Record<string, unknown>)['matchedFields'] as string[] | undefined;\n if (hasExplanation && matched) {\n lines.push(\n `| #${entry.id} | ${entry.time} | ${entry.icon} | ${entry.title} | ~${entry.tokens} | ${matched.join(', ')} |`,\n );\n } else {\n lines.push(\n `| #${entry.id} | ${entry.time} | ${entry.icon} | ${entry.title} | ~${entry.tokens} |`,\n );\n }\n }\n\n lines.push('');\n lines.push(PROGRESSIVE_DISCLOSURE_HINT);\n\n return lines.join('\\n');\n}\n\n/**\n * Format a timeline context around an anchor observation.\n */\nexport function formatTimeline(timeline: TimelineContext): string {\n if (!timeline.anchorEntry) {\n return `Observation #${timeline.anchorId} not found.`;\n }\n\n const lines: string[] = [];\n lines.push(`Timeline around #${timeline.anchorId}:\\n`);\n\n if (timeline.before.length > 0) {\n lines.push('**Before:**');\n lines.push('| ID | Time | T | Title | Tokens |');\n lines.push('|----|------|---|-------|--------|');\n for (const entry of timeline.before) {\n lines.push(`| #${entry.id} | ${entry.time} | ${entry.icon} | ${entry.title} | ~${entry.tokens} |`);\n }\n lines.push('');\n }\n\n lines.push('**► Anchor:**');\n lines.push('| ID | Time | T | Title | Tokens |');\n lines.push('|----|------|---|-------|--------|');\n const a = timeline.anchorEntry;\n lines.push(`| #${a.id} | ${a.time} | ${a.icon} | ${a.title} | ~${a.tokens} |`);\n lines.push('');\n\n if (timeline.after.length > 0) {\n lines.push('**After:**');\n lines.push('| ID | Time | T | Title | Tokens |');\n lines.push('|----|------|---|-------|--------|');\n for (const entry of timeline.after) {\n lines.push(`| #${entry.id} | ${entry.time} | ${entry.icon} | ${entry.title} | ~${entry.tokens} |`);\n }\n lines.push('');\n }\n\n lines.push(PROGRESSIVE_DISCLOSURE_HINT);\n return lines.join('\\n');\n}\n\n/**\n * Format full observation details (Layer 3).\n * Adopted from claude-mem's observation detail format.\n */\nexport function formatObservationDetail(doc: {\n observationId: number;\n type: string;\n title: string;\n narrative: string;\n facts: string;\n filesModified: string;\n concepts: string;\n createdAt: string;\n projectId: string;\n entityName: string;\n}): string {\n const icon = getTypeIcon(doc.type);\n const lines: string[] = [];\n\n lines.push(`#${doc.observationId} ${icon} ${doc.title}`);\n lines.push('─'.repeat(50));\n lines.push(`Date: ${new Date(doc.createdAt).toLocaleString()}`);\n lines.push(`Type: ${doc.type}`);\n lines.push(`Entity: ${doc.entityName}`);\n lines.push(`Project: ${doc.projectId}`);\n lines.push('');\n lines.push(`Narrative: ${doc.narrative}`);\n\n const facts = doc.facts ? doc.facts.split('\\n').filter(Boolean) : [];\n if (facts.length > 0) {\n lines.push('');\n lines.push('Facts:');\n for (const fact of facts) {\n lines.push(`- ${fact}`);\n }\n }\n\n const files = doc.filesModified ? doc.filesModified.split('\\n').filter(Boolean) : [];\n if (files.length > 0) {\n lines.push('');\n lines.push('Files Modified:');\n for (const file of files) {\n lines.push(`- ${file}`);\n }\n }\n\n if (doc.concepts) {\n lines.push('');\n lines.push(`Concepts: ${doc.concepts}`);\n }\n\n return lines.join('\\n');\n}\n\n/** Icon lookup by observation type string */\nfunction getTypeIcon(type: string): string {\n const icons: Record<string, string> = {\n 'session-request': '🎯',\n 'gotcha': '🔴',\n 'problem-solution': '🟡',\n 'how-it-works': '🔵',\n 'what-changed': '🟢',\n 'discovery': '🟣',\n 'why-it-exists': '🟠',\n 'decision': '🟤',\n 'trade-off': '⚖️',\n };\n return icons[type] ?? '❓';\n}\n\n/**\n * Progressive Disclosure instruction hint.\n * Appended to L1/L2 results to teach the agent the workflow.\n */\nconst PROGRESSIVE_DISCLOSURE_HINT = `💡 **Progressive Disclosure:** This index shows WHAT exists and retrieval COST.\n- Use \\`memorix_detail\\` to fetch full observation details by ID\n- Use \\`memorix_timeline\\` to see chronological context around an observation\n- Critical types (🔴 gotcha, 🟤 decision, ⚖️ trade-off) are often worth fetching immediately`;\n","/**\n * Project Detector\n *\n * Identifies the current project using Git remote URL.\n * Source: shared-agent-memory's Git-based project isolation pattern.\n *\n * Extensible: fallback strategies can be added for non-git projects\n * (e.g., package.json name, directory name, etc.)\n */\n\nimport { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { ProjectInfo } from '../types.js';\n\n/**\n * Detect the current project identity from Git remote or fallback.\n * @param cwd - Working directory to detect from (defaults to process.cwd())\n */\nexport function detectProject(cwd?: string): ProjectInfo {\n const basePath = cwd ?? process.cwd();\n // Priority: git root > package.json dir > CWD\n const rootPath = getGitRoot(basePath) ?? findPackageRoot(basePath) ?? basePath;\n const gitRemote = getGitRemote(rootPath);\n\n if (gitRemote) {\n const id = normalizeGitRemote(gitRemote);\n const name = id.split('/').pop() ?? path.basename(rootPath);\n return { id, name, gitRemote, rootPath };\n }\n\n // Validate the root before creating a fallback project.\n // Home dirs, system dirs, etc. get a \"placeholder\" prefix so data is still\n // persisted and tools are usable, but the user gets a warning to set a proper root.\n if (isDangerousRoot(rootPath)) {\n const name = path.basename(rootPath) || 'unknown';\n const id = `placeholder/${name}`;\n console.error(`[memorix] WARNING: cwd \"${rootPath}\" is not a project directory — using degraded mode (${id})`);\n console.error(`[memorix] For best results, set MEMORIX_PROJECT_ROOT or --cwd to your project path.`);\n return { id, name, rootPath };\n }\n\n // Fallback: use \"local/<dirname>\" — works for non-git and empty directories\n const name = path.basename(rootPath);\n const id = `local/${name}`;\n return { id, name, rootPath };\n}\n\n/**\n * Check whether a directory is a dangerous/invalid project root.\n * Returns TRUE for home directories, OS system directories,\n * drive roots, and IDE/tool configuration directories.\n * Returns FALSE for normal directories (including empty ones).\n */\nfunction isDangerousRoot(dirPath: string): boolean {\n const resolved = path.resolve(dirPath);\n const home = path.resolve(os.homedir());\n\n // Reject the home directory itself (e.g., C:\\Users\\Lenovo, /home/user)\n if (resolved === home) return true;\n\n // Reject drive roots (C:\\, D:\\, /)\n if (resolved === path.parse(resolved).root) return true;\n\n // Reject immediate children of home that are IDE/tool config dirs\n const basename = path.basename(resolved).toLowerCase();\n const knownNonProjectDirs = new Set([\n // IDE / editor config dirs\n '.vscode', '.cursor', '.windsurf', '.kiro', '.codex',\n '.gemini', '.claude', '.github', '.git',\n // OS / system dirs\n 'desktop', 'documents', 'downloads', 'pictures', 'videos', 'music',\n 'appdata', 'application data', 'library',\n // Package manager / tool dirs\n 'node_modules', '.npm', '.yarn', '.pnpm-store',\n '.config', '.local', '.cache', '.ssh', '.memorix',\n ]);\n if (knownNonProjectDirs.has(basename)) {\n const parent = path.resolve(path.dirname(resolved));\n // Only block if it's directly under home or a drive root\n if (parent === home || parent === path.parse(parent).root) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Walk up from cwd to find the nearest directory containing package.json.\n * Useful for non-git projects where the MCP server CWD may differ from project root.\n */\nfunction findPackageRoot(cwd: string): string | null {\n let dir = path.resolve(cwd);\n const root = path.parse(dir).root;\n while (dir !== root) {\n // Stop walking if we hit a dangerous directory (home dir, system dir)\n if (isDangerousRoot(dir)) return null;\n if (existsSync(path.join(dir, 'package.json'))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n return null;\n}\n\n/**\n * Get the Git repository root directory.\n * Returns null if not inside a git repository.\n */\nfunction getGitRoot(cwd: string): string | null {\n // Fast path: walk up to find .git directory (instant, no subprocess)\n let dir = path.resolve(cwd);\n const fsRoot = path.parse(dir).root;\n while (dir !== fsRoot) {\n if (existsSync(path.join(dir, '.git'))) return dir;\n dir = path.dirname(dir);\n }\n\n // Slow path: git CLI for edge cases (submodules, worktrees, bare repos)\n try {\n const root = execSync('git -c safe.directory=* rev-parse --show-toplevel', {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 5000,\n }).trim();\n return root || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the Git remote URL for the given directory.\n * Returns null if not a git repository or no remote configured.\n */\nfunction getGitRemote(cwd: string): string | null {\n // Fast path: read .git/config directly (instant, no subprocess)\n const fsRemote = readGitConfigRemote(cwd);\n if (fsRemote) return fsRemote;\n\n // Slow path: git CLI for edge cases (submodules, worktrees, non-standard layouts)\n try {\n const remote = execSync('git -c safe.directory=* remote get-url origin', {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 5000,\n }).trim();\n return remote || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Fallback: parse remote.origin.url from .git/config when git CLI fails.\n * Handles Windows \"dubious ownership\" and other permission issues.\n */\nfunction readGitConfigRemote(cwd: string): string | null {\n try {\n const configPath = path.join(cwd, '.git', 'config');\n if (!existsSync(configPath)) return null;\n const content = readFileSync(configPath, 'utf-8');\n // Parse INI-style: [remote \"origin\"] section, url = ...\n const remoteMatch = content.match(/\\[remote\\s+\"origin\"\\]([\\s\\S]*?)(?=\\n\\[|$)/);\n if (!remoteMatch) return null;\n const urlMatch = remoteMatch[1].match(/^\\s*url\\s*=\\s*(.+)$/m);\n return urlMatch ? urlMatch[1].trim() : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Normalize a Git remote URL to a consistent project ID.\n *\n * Examples:\n * https://github.com/user/repo.git → user/repo\n * git@github.com:user/repo.git → user/repo\n * ssh://git@github.com/user/repo → user/repo\n */\nfunction normalizeGitRemote(remote: string): string {\n let normalized = remote;\n\n // Remove trailing .git\n normalized = normalized.replace(/\\.git$/, '');\n\n // Handle SSH format: git@github.com:user/repo\n const sshMatch = normalized.match(/^[\\w-]+@[\\w.-]+:(.+)$/);\n if (sshMatch) {\n return sshMatch[1];\n }\n\n // Handle HTTPS/SSH URL format\n try {\n const url = new URL(normalized);\n // Remove leading slash\n return url.pathname.replace(/^\\//, '');\n } catch {\n // If URL parsing fails, take last two segments\n const segments = normalized.split('/').filter(Boolean);\n return segments.slice(-2).join('/');\n }\n}\n","/**\n * Rules Syncer\n *\n * Core sync engine for cross-agent rule synchronization.\n * Scans project for rule files from all supported agents,\n * deduplicates by content hash, detects conflicts, and\n * generates output in any target agent format.\n *\n * This is the ~15% original logic in Memorix — dedup and\n * conflict detection are not found in any existing tool.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { UnifiedRule, RuleSource, RuleFormatAdapter } from '../types.js';\nimport { CursorAdapter } from './adapters/cursor.js';\nimport { ClaudeCodeAdapter } from './adapters/claude-code.js';\nimport { CodexAdapter } from './adapters/codex.js';\nimport { WindsurfAdapter } from './adapters/windsurf.js';\nimport { AntigravityAdapter } from './adapters/antigravity.js';\nimport { CopilotAdapter } from './adapters/copilot.js';\nimport { KiroAdapter } from './adapters/kiro.js';\nimport { TraeAdapter } from './adapters/trae.js';\n\n/** A detected conflict between two rules */\nexport interface RuleConflict {\n ruleA: UnifiedRule;\n ruleB: UnifiedRule;\n reason: string;\n}\n\n/** Sync status report */\nexport interface SyncStatus {\n totalRules: number;\n uniqueRules: number;\n sources: RuleSource[];\n conflicts: RuleConflict[];\n}\n\n/** File scan patterns for each adapter */\ninterface ScanEntry {\n adapter: RuleFormatAdapter;\n paths: string[];\n}\n\nexport class RulesSyncer {\n private readonly projectRoot: string;\n private readonly adapters: Map<RuleSource, RuleFormatAdapter>;\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n this.adapters = new Map();\n\n const all: RuleFormatAdapter[] = [\n new CursorAdapter(),\n new ClaudeCodeAdapter(),\n new CodexAdapter(),\n new WindsurfAdapter(),\n new AntigravityAdapter(),\n new CopilotAdapter(),\n new KiroAdapter(),\n new TraeAdapter(),\n ];\n for (const a of all) {\n this.adapters.set(a.source, a);\n }\n }\n\n /** Scan the project root for all known rule files and parse them */\n async scanRules(): Promise<UnifiedRule[]> {\n const rules: UnifiedRule[] = [];\n\n const scanEntries = this.buildScanEntries();\n\n for (const entry of scanEntries) {\n for (const scanPath of entry.paths) {\n const found = await this.findFiles(scanPath);\n for (const filePath of found) {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const relativePath = path.relative(this.projectRoot, filePath).replace(/\\\\/g, '/');\n const parsed = entry.adapter.parse(relativePath, content);\n rules.push(...parsed);\n } catch {\n // Skip unreadable files\n }\n }\n }\n }\n\n return rules;\n }\n\n /** Remove duplicate rules by content hash, keeping highest priority */\n deduplicateRules(rules: UnifiedRule[]): UnifiedRule[] {\n const byHash = new Map<string, UnifiedRule>();\n\n for (const rule of rules) {\n const existing = byHash.get(rule.hash);\n if (!existing || rule.priority > existing.priority) {\n byHash.set(rule.hash, rule);\n }\n }\n\n return Array.from(byHash.values());\n }\n\n /** Detect conflicts: rules with overlapping paths but different content */\n detectConflicts(rules: UnifiedRule[]): RuleConflict[] {\n const conflicts: RuleConflict[] = [];\n\n for (let i = 0; i < rules.length; i++) {\n for (let j = i + 1; j < rules.length; j++) {\n const a = rules[i];\n const b = rules[j];\n\n // Only compare rules from different sources\n if (a.source === b.source) continue;\n // Only compare if both have overlapping paths\n if (a.scope === 'path-specific' && b.scope === 'path-specific') {\n if (this.pathsOverlap(a.paths || [], b.paths || [])) {\n conflicts.push({\n ruleA: a,\n ruleB: b,\n reason: `Overlapping paths: ${a.source} vs ${b.source}`,\n });\n }\n }\n }\n }\n\n return conflicts;\n }\n\n /** Generate rule files for a target agent format */\n generateForTarget(\n rules: UnifiedRule[],\n target: RuleSource,\n ): { filePath: string; content: string }[] {\n const adapter = this.adapters.get(target);\n if (!adapter) {\n throw new Error(`No adapter for target: ${target}`);\n }\n return adapter.generate(rules);\n }\n\n /** Get a full sync status report */\n async syncStatus(): Promise<SyncStatus> {\n const rules = await this.scanRules();\n const deduped = this.deduplicateRules(rules);\n const conflicts = this.detectConflicts(deduped);\n const sources = [...new Set(rules.map(r => r.source))];\n\n return {\n totalRules: rules.length,\n uniqueRules: deduped.length,\n sources,\n conflicts,\n };\n }\n\n /** Build scan entries mapping adapters to their file search paths */\n private buildScanEntries(): ScanEntry[] {\n const entries: ScanEntry[] = [];\n\n for (const adapter of this.adapters.values()) {\n const absolutePaths = adapter.filePatterns.map(p =>\n path.join(this.projectRoot, p),\n );\n entries.push({ adapter, paths: absolutePaths });\n }\n\n return entries;\n }\n\n /** Find files matching a glob-like path (simple implementation) */\n private async findFiles(pattern: string): Promise<string[]> {\n const dir = path.dirname(pattern);\n const fileGlob = path.basename(pattern);\n\n try {\n const stat = await fs.stat(dir);\n if (!stat.isDirectory()) {\n // It's a direct file path\n try {\n await fs.access(pattern);\n return [pattern];\n } catch {\n return [];\n }\n }\n } catch {\n // If dir doesn't exist, check if pattern itself is a file\n try {\n await fs.access(pattern);\n return [pattern];\n } catch {\n return [];\n }\n }\n\n // If it's a glob pattern (contains *), list dir and filter\n if (fileGlob.includes('*')) {\n try {\n const files = await fs.readdir(dir);\n const ext = fileGlob.replace('*', '');\n return files\n .filter(f => ext ? f.endsWith(ext) : true)\n .map(f => path.join(dir, f));\n } catch {\n return [];\n }\n }\n\n // Direct file\n try {\n await fs.access(path.join(dir, fileGlob));\n return [path.join(dir, fileGlob)];\n } catch {\n return [];\n }\n }\n\n /** Check if two sets of glob paths overlap (simplified: exact match) */\n private pathsOverlap(a: string[], b: string[]): boolean {\n for (const pa of a) {\n for (const pb of b) {\n if (pa === pb) return true;\n }\n }\n return false;\n }\n}\n","/**\n * Cursor Rule Format Adapter\n *\n * Parses and generates rules in Cursor's formats:\n * - .cursor/rules/*.mdc (Markdown + frontmatter with description, alwaysApply, globs)\n * - .cursorrules (legacy plain text)\n * - AGENTS.md (pure Markdown)\n *\n * Source: Cursor official documentation on Project Rules.\n */\n\nimport matter from 'gray-matter';\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class CursorAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'cursor';\n\n readonly filePatterns = [\n '.cursor/rules/*.mdc',\n '.cursorrules',\n 'AGENTS.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n if (filePath.endsWith('.mdc')) {\n return this.parseMdc(filePath, content);\n }\n if (filePath === '.cursorrules' || filePath.endsWith('/.cursorrules')) {\n return this.parseLegacy(filePath, content);\n }\n if (filePath.endsWith('AGENTS.md')) {\n return this.parseAgentsMd(filePath, content);\n }\n return [];\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n return rules.map((rule, i) => {\n const fm: Record<string, unknown> = {};\n if (rule.description) fm.description = rule.description;\n if (rule.alwaysApply !== undefined) fm.alwaysApply = rule.alwaysApply;\n if (rule.paths && rule.paths.length > 0) fm.globs = rule.paths;\n\n const fileName = rule.id\n .replace(/^cursor:/, '')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n || `rule-${i}`;\n\n const body = Object.keys(fm).length > 0\n ? matter.stringify(rule.content, fm)\n : rule.content;\n\n return {\n filePath: `.cursor/rules/${fileName}.mdc`,\n content: body,\n };\n });\n }\n\n private parseMdc(filePath: string, content: string): UnifiedRule[] {\n const { data, content: body } = matter(content);\n const trimmed = body.trim();\n if (!trimmed) return [];\n\n const globs = data.globs as string[] | undefined;\n const hasGlobs = Array.isArray(globs) && globs.length > 0;\n const alwaysApply = data.alwaysApply === true;\n\n let scope: UnifiedRule['scope'] = 'project';\n if (alwaysApply) scope = 'global';\n else if (hasGlobs) scope = 'path-specific';\n\n return [{\n id: generateRuleId('cursor', filePath),\n content: trimmed,\n description: data.description as string | undefined,\n source: 'cursor',\n scope,\n paths: hasGlobs ? globs : undefined,\n alwaysApply,\n priority: alwaysApply ? 10 : 5,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseLegacy(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('cursor', filePath),\n content: trimmed,\n source: 'cursor',\n scope: 'project',\n priority: 3,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseAgentsMd(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('cursor', filePath),\n content: trimmed,\n source: 'cursor',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n}\n","/**\n * Rules Utilities\n *\n * Shared helpers for rule parsing: content hashing, ID generation, etc.\n */\n\nimport { createHash } from 'node:crypto';\n\n/** Generate a deterministic content hash for deduplication */\nexport function hashContent(content: string): string {\n return createHash('sha256')\n .update(content.trim())\n .digest('hex')\n .substring(0, 16);\n}\n\n/** Generate a rule ID from source + file path */\nexport function generateRuleId(source: string, filePath: string): string {\n const sanitized = filePath.replace(/[\\/\\\\]/g, '-').replace(/^\\./, '');\n return `${source}:${sanitized}`;\n}\n","/**\n * Claude Code Rule Format Adapter\n *\n * Parses and generates rules in Claude Code's formats:\n * - CLAUDE.md / .claude/CLAUDE.md (project-level Markdown)\n * - .claude/rules/*.md (Markdown with optional `paths` frontmatter)\n *\n * Source: Claude Code official documentation.\n */\n\nimport matter from 'gray-matter';\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class ClaudeCodeAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'claude-code';\n\n readonly filePatterns = [\n 'CLAUDE.md',\n '.claude/CLAUDE.md',\n '.claude/rules/*.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n // .claude/rules/*.md may have `paths` frontmatter\n if (filePath.includes('.claude/rules/')) {\n return this.parseModularRule(filePath, content);\n }\n // CLAUDE.md — project-level\n return this.parseClaudeMd(filePath, content);\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n const projectRules = rules.filter(r => r.scope !== 'path-specific');\n const pathRules = rules.filter(r => r.scope === 'path-specific');\n\n const files: { filePath: string; content: string }[] = [];\n\n if (projectRules.length > 0) {\n files.push({\n filePath: 'CLAUDE.md',\n content: projectRules.map(r => r.content).join('\\n\\n'),\n });\n }\n\n for (const rule of pathRules) {\n const fm: Record<string, unknown> = {};\n if (rule.paths && rule.paths.length > 0) fm.paths = rule.paths;\n\n const fileName = rule.id\n .replace(/^claude-code:/, '')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n || 'rule';\n\n files.push({\n filePath: `.claude/rules/${fileName}.md`,\n content: Object.keys(fm).length > 0\n ? matter.stringify(rule.content, fm)\n : rule.content,\n });\n }\n\n return files;\n }\n\n private parseClaudeMd(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('claude-code', filePath),\n content: trimmed,\n source: 'claude-code',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseModularRule(filePath: string, content: string): UnifiedRule[] {\n const { data, content: body } = matter(content);\n const trimmed = body.trim();\n if (!trimmed) return [];\n\n const paths = data.paths as string[] | undefined;\n const hasPaths = Array.isArray(paths) && paths.length > 0;\n\n return [{\n id: generateRuleId('claude-code', filePath),\n content: trimmed,\n description: data.description as string | undefined,\n source: 'claude-code',\n scope: hasPaths ? 'path-specific' : 'project',\n paths: hasPaths ? paths : undefined,\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n}\n","/**\n * OpenAI Codex Rule Format Adapter\n *\n * Parses and generates rules in Codex's formats:\n * - .agents/skills/[name]/SKILL.md (Markdown + frontmatter with name, description)\n * - AGENTS.md (pure Markdown)\n *\n * Source: OpenAI Codex Skills documentation.\n */\n\nimport matter from 'gray-matter';\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class CodexAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'codex';\n\n readonly filePatterns = [\n '.agents/skills/*/SKILL.md',\n 'AGENTS.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n if (filePath.includes('SKILL.md')) {\n return this.parseSkillMd(filePath, content);\n }\n if (filePath.endsWith('AGENTS.md')) {\n return this.parseAgentsMd(filePath, content);\n }\n return [];\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n return rules.map((rule, i) => {\n const skillName = rule.id\n .replace(/^codex:/, '')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n || `skill-${i}`;\n\n const fm: Record<string, unknown> = {\n name: skillName,\n };\n\n // Codex needs description to know WHEN to trigger the skill.\n // If no description exists, auto-generate from content (first 120 chars).\n if (rule.description) {\n fm.description = rule.description;\n } else {\n fm.description = this.autoDescription(rule.content);\n }\n\n return {\n filePath: `.agents/skills/${skillName}/SKILL.md`,\n content: matter.stringify(rule.content, fm),\n };\n });\n }\n\n /** Extract a short description from rule content for Codex skill triggering */\n private autoDescription(content: string): string {\n // Take first meaningful line, strip markdown formatting\n const lines = content.split('\\n').map(l => l.trim()).filter(Boolean);\n const first = lines[0]?.replace(/^#+\\s*/, '').replace(/^[-*]\\s*/, '') || 'Project rules';\n if (first.length <= 120) return first;\n return first.substring(0, 117) + '...';\n }\n\n private parseSkillMd(filePath: string, content: string): UnifiedRule[] {\n const { data, content: body } = matter(content);\n const trimmed = body.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('codex', filePath),\n content: trimmed,\n description: (data.description as string) || undefined,\n source: 'codex',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseAgentsMd(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('codex', filePath),\n content: trimmed,\n source: 'codex',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n}\n","/**\n * Windsurf Rule Format Adapter\n *\n * Parses and generates rules in Windsurf's formats:\n * - .windsurfrules (legacy plain text)\n * - .windsurf/rules/*.md (Markdown with optional frontmatter)\n *\n * Source: Windsurf/Codeium documentation.\n */\n\nimport matter from 'gray-matter';\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class WindsurfAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'windsurf';\n\n readonly filePatterns = [\n '.windsurfrules',\n '.windsurf/rules/*.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n if (filePath === '.windsurfrules' || filePath.endsWith('/.windsurfrules')) {\n return this.parseLegacy(filePath, content);\n }\n if (filePath.includes('.windsurf/rules/')) {\n return this.parseModularRule(filePath, content);\n }\n return [];\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n return rules.map((rule, i) => {\n const fm: Record<string, unknown> = {};\n if (rule.description) fm.description = rule.description;\n\n const fileName = rule.id\n .replace(/^windsurf:/, '')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n || `rule-${i}`;\n\n const body = Object.keys(fm).length > 0\n ? matter.stringify(rule.content, fm)\n : rule.content;\n\n return {\n filePath: `.windsurf/rules/${fileName}.md`,\n content: body,\n };\n });\n }\n\n private parseLegacy(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('windsurf', filePath),\n content: trimmed,\n source: 'windsurf',\n scope: 'project',\n priority: 3,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseModularRule(filePath: string, content: string): UnifiedRule[] {\n const { data, content: body } = matter(content);\n const trimmed = body.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('windsurf', filePath),\n content: trimmed,\n description: data.description as string | undefined,\n source: 'windsurf',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n}\n","/**\r\n * Antigravity IDE Rule Format Adapter\r\n *\r\n * Parses and generates rules in Antigravity's formats:\r\n * - GEMINI.md (global rules, similar to CLAUDE.md)\r\n * - .agent/rules/*.md (workspace rules, Markdown with optional frontmatter)\r\n * - .agent/skills/[name]/SKILL.md (skills, Markdown + YAML frontmatter)\r\n *\r\n * Source: Antigravity official documentation (https://antigravity.google/docs/agent/rules)\r\n *\r\n * Note: Antigravity is Google's agent-first IDE, a VS Code fork.\r\n * Global rules: ~/.gemini/GEMINI.md\r\n * Workspace rules: <project>/.agent/rules/*.md\r\n * Skills: <project>/.agent/skills/[name]/SKILL.md\r\n * Workflows: <project>/.agent/workflows/*.md\r\n */\r\n\r\nimport matter from 'gray-matter';\r\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\r\nimport { hashContent, generateRuleId } from '../utils.js';\r\n\r\nexport class AntigravityAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'antigravity';\r\n\r\n readonly filePatterns = [\r\n 'GEMINI.md',\r\n '.agent/rules/*.md',\r\n '.agent/skills/*/SKILL.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n // .agent/skills/*/SKILL.md — skill files with frontmatter\r\n if (filePath.includes('SKILL.md')) {\r\n return this.parseSkillMd(filePath, content);\r\n }\r\n // .agent/rules/*.md — workspace rules\r\n if (filePath.includes('.agent/rules/')) {\r\n return this.parseAgentRule(filePath, content);\r\n }\r\n // GEMINI.md — global project-level rules\r\n if (filePath === 'GEMINI.md' || filePath.endsWith('/GEMINI.md')) {\r\n return this.parseGeminiMd(filePath, content);\r\n }\r\n return [];\r\n }\r\n\r\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\r\n const projectRules = rules.filter(r => r.scope !== 'path-specific');\r\n const pathRules = rules.filter(r => r.scope === 'path-specific');\r\n\r\n const files: { filePath: string; content: string }[] = [];\r\n\r\n // Generate workspace rules as .agent/rules/*.md\r\n for (const rule of [...projectRules, ...pathRules]) {\r\n const fm: Record<string, unknown> = {};\r\n if (rule.description) fm.description = rule.description;\r\n\r\n const fileName = rule.id\r\n .replace(/^antigravity:/, '')\r\n .replace(/[^a-zA-Z0-9-_]/g, '-')\r\n || 'rule';\r\n\r\n const body = Object.keys(fm).length > 0\r\n ? matter.stringify(rule.content, fm)\r\n : rule.content;\r\n\r\n files.push({\r\n filePath: `.agent/rules/${fileName}.md`,\r\n content: body,\r\n });\r\n }\r\n\r\n return files;\r\n }\r\n\r\n private parseGeminiMd(filePath: string, content: string): UnifiedRule[] {\r\n const trimmed = content.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('antigravity', filePath),\r\n content: trimmed,\r\n source: 'antigravity',\r\n scope: 'global',\r\n priority: 10,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseAgentRule(filePath: string, content: string): UnifiedRule[] {\r\n const { data, content: body } = matter(content);\r\n const trimmed = body.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('antigravity', filePath),\r\n content: trimmed,\r\n description: data.description as string | undefined,\r\n source: 'antigravity',\r\n scope: 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseSkillMd(filePath: string, content: string): UnifiedRule[] {\r\n const { data, content: body } = matter(content);\r\n const trimmed = body.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('antigravity', filePath),\r\n content: trimmed,\r\n description: (data.description as string) || undefined,\r\n source: 'antigravity',\r\n scope: 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n}\r\n","/**\r\n * GitHub Copilot Rule Format Adapter\r\n *\r\n * Parses and generates rules in Copilot's formats:\r\n * - .github/copilot-instructions.md (repository-wide instructions, plain Markdown)\r\n * - .github/instructions/*.instructions.md (path-specific, YAML frontmatter with `applyTo` glob)\r\n *\r\n * Source: https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot\r\n */\r\n\r\nimport matter from 'gray-matter';\r\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\r\nimport { hashContent, generateRuleId } from '../utils.js';\r\n\r\nexport class CopilotAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'copilot';\r\n\r\n readonly filePatterns = [\r\n '.github/copilot-instructions.md',\r\n '.github/instructions/*.instructions.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n // Path-specific instruction files (.github/instructions/*.instructions.md)\r\n if (filePath.includes('.instructions.md') && filePath.includes('.github/instructions')) {\r\n return this.parsePathSpecific(filePath, content);\r\n }\r\n // Repository-wide instructions (.github/copilot-instructions.md)\r\n if (filePath.includes('copilot-instructions.md')) {\r\n return this.parseRepoWide(filePath, content);\r\n }\r\n return [];\r\n }\r\n\r\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\r\n // If only one rule with no path-specific globs, output as copilot-instructions.md\r\n if (rules.length === 1 && (!rules[0].paths || rules[0].paths.length === 0)) {\r\n return [{\r\n filePath: '.github/copilot-instructions.md',\r\n content: rules[0].content,\r\n }];\r\n }\r\n\r\n // Multiple rules → output as path-specific instruction files\r\n return rules.map((rule, i) => {\r\n const fm: Record<string, unknown> = {};\r\n\r\n // Preserve applyTo if available\r\n if (rule.paths && rule.paths.length > 0) {\r\n fm.applyTo = rule.paths.join(',');\r\n }\r\n if (rule.description) {\r\n fm.description = rule.description;\r\n }\r\n\r\n const fileName = rule.id\r\n .replace(/^copilot:/, '')\r\n .replace(/[^a-zA-Z0-9-_]/g, '-')\r\n || `instruction-${i}`;\r\n\r\n const body = Object.keys(fm).length > 0\r\n ? matter.stringify(rule.content, fm)\r\n : rule.content;\r\n\r\n return {\r\n filePath: `.github/instructions/${fileName}.instructions.md`,\r\n content: body,\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * Parse repository-wide .github/copilot-instructions.md\r\n * This is plain Markdown with no frontmatter.\r\n */\r\n private parseRepoWide(filePath: string, content: string): UnifiedRule[] {\r\n const trimmed = content.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('copilot', filePath),\r\n content: trimmed,\r\n description: 'Repository-wide Copilot instructions',\r\n source: 'copilot',\r\n scope: 'project',\r\n priority: 3,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n /**\r\n * Parse path-specific .github/instructions/*.instructions.md\r\n * These have YAML frontmatter with `applyTo` glob pattern(s).\r\n */\r\n private parsePathSpecific(filePath: string, content: string): UnifiedRule[] {\r\n const { data, content: body } = matter(content);\r\n const trimmed = body.trim();\r\n if (!trimmed) return [];\r\n\r\n const applyTo = data.applyTo as string | undefined;\r\n const hasApplyTo = !!applyTo;\r\n\r\n const rule: UnifiedRule = {\r\n id: generateRuleId('copilot', filePath),\r\n content: trimmed,\r\n source: 'copilot',\r\n scope: hasApplyTo ? 'path-specific' : 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n };\r\n\r\n // Extract applyTo glob pattern(s) → store in paths[]\r\n if (hasApplyTo) {\r\n rule.paths = applyTo!.split(',').map(p => p.trim());\r\n }\r\n\r\n // Extract description if present\r\n if (data.description) {\r\n rule.description = data.description as string;\r\n }\r\n\r\n return [rule];\r\n }\r\n}\r\n","/**\r\n * Kiro Rule Format Adapter\r\n *\r\n * Parses and generates rules in Kiro's formats:\r\n * - .kiro/steering/*.md (Markdown steering rules with optional frontmatter)\r\n * - AGENTS.md (always included, pure Markdown)\r\n *\r\n * Source: Kiro official documentation on Steering Rules.\r\n * https://kiro.dev/docs/steering/\r\n *\r\n * Kiro uses \".kiro/steering/\" for project-level rules\r\n * and \"~/.kiro/steering/\" for user-level (global) rules.\r\n *\r\n * Frontmatter inclusion modes:\r\n * - always (default): loaded into every interaction\r\n * - fileMatch + fileMatchPattern: conditional on file globs\r\n * - manual: on-demand via #name in chat\r\n * - auto + name + description: auto-included when relevant\r\n */\r\n\r\nimport matter from 'gray-matter';\r\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\r\nimport { hashContent, generateRuleId } from '../utils.js';\r\n\r\n/** Kiro inclusion mode values */\r\ntype KiroInclusion = 'always' | 'fileMatch' | 'manual' | 'auto';\r\n\r\nexport class KiroAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'kiro';\r\n\r\n readonly filePatterns = [\r\n '.kiro/steering/*.md',\r\n 'AGENTS.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n if (filePath.includes('.kiro/steering/')) {\r\n return this.parseSteeringRule(filePath, content);\r\n }\r\n if (filePath.endsWith('AGENTS.md')) {\r\n return this.parseAgentsMd(filePath, content);\r\n }\r\n return [];\r\n }\r\n\r\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\r\n return rules.map((rule, i) => {\r\n const fm: Record<string, unknown> = {};\r\n if (rule.description) fm.description = rule.description;\r\n\r\n // Map unified scope → Kiro inclusion mode\r\n if (rule.paths && rule.paths.length > 0) {\r\n fm.inclusion = 'fileMatch';\r\n fm.fileMatchPattern = rule.paths.length === 1\r\n ? rule.paths[0]\r\n : rule.paths;\r\n } else if (rule.alwaysApply) {\r\n fm.inclusion = 'always';\r\n }\r\n\r\n const fileName = rule.id\r\n .replace(/^kiro:/, '')\r\n .replace(/[^a-zA-Z0-9-_]/g, '-')\r\n || `rule-${i}`;\r\n\r\n const body = Object.keys(fm).length > 0\r\n ? matter.stringify(rule.content, fm)\r\n : rule.content;\r\n\r\n return {\r\n filePath: `.kiro/steering/${fileName}.md`,\r\n content: body,\r\n };\r\n });\r\n }\r\n\r\n private parseSteeringRule(filePath: string, content: string): UnifiedRule[] {\r\n const { data, content: body } = matter(content);\r\n const trimmed = body.trim();\r\n if (!trimmed) return [];\r\n\r\n // Kiro uses \"inclusion\" field: always | fileMatch | manual | auto\r\n const inclusion = (data.inclusion as KiroInclusion | undefined) ?? 'always';\r\n const alwaysApply = inclusion === 'always' || inclusion === 'auto';\r\n\r\n // fileMatchPattern can be a string or string[]\r\n let paths: string[] | undefined;\r\n if (inclusion === 'fileMatch' && data.fileMatchPattern) {\r\n paths = Array.isArray(data.fileMatchPattern)\r\n ? data.fileMatchPattern\r\n : [data.fileMatchPattern];\r\n }\r\n\r\n let scope: UnifiedRule['scope'] = 'project';\r\n if (alwaysApply) scope = 'global';\r\n else if (paths && paths.length > 0) scope = 'path-specific';\r\n\r\n return [{\r\n id: generateRuleId('kiro', filePath),\r\n content: trimmed,\r\n description: data.description as string | undefined,\r\n source: 'kiro',\r\n scope,\r\n paths,\r\n alwaysApply,\r\n priority: alwaysApply ? 10 : 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseAgentsMd(filePath: string, content: string): UnifiedRule[] {\r\n const trimmed = content.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('kiro', filePath),\r\n content: trimmed,\r\n source: 'kiro',\r\n scope: 'project',\r\n alwaysApply: true,\r\n priority: 10,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n}\r\n\r\n","/**\n * Trae IDE Rule Format Adapter\n *\n * Parses and generates rules in Trae's format:\n * - .trae/rules/project_rules.md (project-level rules, plain Markdown)\n *\n * Trae also supports user-level rules (user_rules.md) created via the UI,\n * but those are managed by Trae itself and not project-scoped.\n *\n * Rules are plain Markdown — no frontmatter, no special syntax.\n * Project rules override personal rules when there are conflicts.\n *\n * Source: https://docs.trae.ai/ide/rules\n */\n\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class TraeAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'trae';\n\n readonly filePatterns = [\n '.trae/rules/project_rules.md',\n '.trae/rules/*.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n const isProjectRules = filePath.includes('project_rules.md');\n\n return [{\n id: generateRuleId('trae', filePath),\n content: trimmed,\n description: isProjectRules ? 'Trae project rules' : undefined,\n source: 'trae',\n scope: 'project',\n alwaysApply: true,\n priority: isProjectRules ? 10 : 5,\n hash: hashContent(trimmed),\n }];\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n if (rules.length === 0) return [];\n\n // Trae uses a single project_rules.md file — merge all rules into one\n const combined = rules.map(r => r.content).join('\\n\\n---\\n\\n');\n\n return [{\n filePath: '.trae/rules/project_rules.md',\n content: combined,\n }];\n }\n}\n","import { readFileSync, readdirSync, existsSync, cpSync, mkdirSync } from 'node:fs';\nimport { join, basename } from 'node:path';\nimport { homedir } from 'node:os';\nimport type {\n AgentTarget,\n MCPServerEntry,\n MCPConfigAdapter,\n WorkflowEntry,\n WorkspaceSyncResult,\n RuleSource,\n SkillEntry,\n SkillConflict,\n} from '../types.js';\nimport { WindsurfMCPAdapter } from './mcp-adapters/windsurf.js';\nimport { CursorMCPAdapter } from './mcp-adapters/cursor.js';\nimport { CodexMCPAdapter } from './mcp-adapters/codex.js';\nimport { ClaudeCodeMCPAdapter } from './mcp-adapters/claude-code.js';\nimport { CopilotMCPAdapter } from './mcp-adapters/copilot.js';\nimport { AntigravityMCPAdapter } from './mcp-adapters/antigravity.js';\nimport { KiroMCPAdapter } from './mcp-adapters/kiro.js';\nimport { OpenCodeMCPAdapter } from './mcp-adapters/opencode.js';\nimport { TraeMCPAdapter } from './mcp-adapters/trae.js';\nimport { WorkflowSyncer } from './workflow-sync.js';\nimport { RulesSyncer } from '../rules/syncer.js';\nimport { sanitize } from './sanitizer.js';\nimport { WorkspaceSyncApplier, type ApplyResult } from './applier.js';\n\n/** Scan result from workspace analysis */\nexport interface WorkspaceScanResult {\n mcpConfigs: Record<AgentTarget, MCPServerEntry[]>;\n workflows: WorkflowEntry[];\n rulesCount: number;\n skills: SkillEntry[];\n skillConflicts: SkillConflict[];\n}\n\n/**\n * WorkspaceSyncEngine — orchestrates cross-agent workspace migration.\n *\n * Capabilities:\n * 1. MCP config sync (JSON ↔ TOML across 4 agents)\n * 2. Workflow sync (Windsurf workflows → Codex skills / Cursor rules / CLAUDE.md)\n * 3. Rules sync (via existing RulesSyncer)\n */\nexport class WorkspaceSyncEngine {\n private adapters: Map<AgentTarget, MCPConfigAdapter>;\n private workflowSyncer: WorkflowSyncer;\n private rulesSyncer: RulesSyncer;\n\n constructor(private projectRoot: string) {\n this.adapters = new Map<AgentTarget, MCPConfigAdapter>([\n ['windsurf', new WindsurfMCPAdapter()],\n ['cursor', new CursorMCPAdapter()],\n ['codex', new CodexMCPAdapter()],\n ['claude-code', new ClaudeCodeMCPAdapter()],\n ['copilot', new CopilotMCPAdapter()],\n ['antigravity', new AntigravityMCPAdapter()],\n ['kiro', new KiroMCPAdapter()],\n ['opencode', new OpenCodeMCPAdapter()],\n ['trae', new TraeMCPAdapter()],\n ]);\n this.workflowSyncer = new WorkflowSyncer();\n this.rulesSyncer = new RulesSyncer(projectRoot);\n }\n\n /**\n * Scan the workspace for all agent configs, workflows, and rules.\n */\n async scan(): Promise<WorkspaceScanResult> {\n const mcpConfigs: Record<AgentTarget, MCPServerEntry[]> = {\n windsurf: [],\n cursor: [],\n codex: [],\n 'claude-code': [],\n copilot: [],\n antigravity: [],\n kiro: [],\n opencode: [],\n trae: [],\n };\n\n // Scan MCP configs from each agent (merge all paths, dedup by name)\n for (const [target, adapter] of this.adapters) {\n const configPath = adapter.getConfigPath(this.projectRoot);\n const globalPath = adapter.getConfigPath();\n\n const pathsToCheck = [configPath, globalPath];\n\n // Antigravity has an additional config at ~/.gemini/antigravity/mcp_config.json\n if (target === 'antigravity') {\n pathsToCheck.push(join(homedir(), '.gemini', 'antigravity', 'mcp_config.json'));\n }\n\n const merged = new Map<string, MCPServerEntry>();\n for (const path of pathsToCheck) {\n if (existsSync(path)) {\n try {\n const content = readFileSync(path, 'utf-8');\n const servers = adapter.parse(content);\n for (const s of servers) {\n if (!merged.has(s.name)) merged.set(s.name, s);\n }\n } catch {\n // Skip unreadable configs\n }\n }\n }\n if (merged.size > 0) {\n mcpConfigs[target] = Array.from(merged.values());\n }\n }\n\n // Scan Windsurf workflows\n const workflows = this.scanWorkflows();\n\n // Scan rules\n let rulesCount = 0;\n try {\n const rules = await this.rulesSyncer.scanRules();\n rulesCount = rules.length;\n } catch {\n // Rules scan may fail if no rules exist\n }\n\n // Scan skills across all agents\n const { skills, conflicts: skillConflicts } = this.scanSkills();\n\n return { mcpConfigs, workflows, rulesCount, skills, skillConflicts };\n }\n\n /**\n * Migrate workspace configs to a target agent format.\n * @param items — optional list of specific item names (MCP servers / skills) to sync.\n * When provided, only matching items are included. Omit to sync all.\n */\n async migrate(target: AgentTarget, items?: string[]): Promise<WorkspaceSyncResult> {\n const scan = await this.scan();\n const result: WorkspaceSyncResult = {\n mcpServers: { scanned: [], generated: [] },\n workflows: { scanned: [], generated: [] },\n rules: { scanned: 0, generated: 0 },\n skills: { scanned: [], conflicts: [], copied: [], skipped: [] },\n };\n\n const itemFilter = items && items.length > 0\n ? new Set(items.map(i => i.toLowerCase()))\n : null;\n\n // 1. Merge all MCP servers from all sources (dedup by name)\n const allServers = new Map<string, MCPServerEntry>();\n for (const servers of Object.values(scan.mcpConfigs)) {\n for (const s of servers) {\n if (!allServers.has(s.name)) {\n if (!itemFilter || itemFilter.has(s.name.toLowerCase())) {\n allServers.set(s.name, s);\n }\n }\n }\n }\n result.mcpServers.scanned = Array.from(allServers.values());\n\n // Generate target MCP config (sanitize sensitive values in output)\n if (result.mcpServers.scanned.length > 0) {\n const adapter = this.adapters.get(target)!;\n const configPath = adapter.getConfigPath(this.projectRoot);\n let configContent: string;\n\n // For agents whose config file is shared (e.g. .gemini/settings.json\n // contains both hooks and mcpServers), merge instead of overwrite.\n if (target === 'antigravity' && existsSync(configPath)) {\n try {\n const existing = JSON.parse(readFileSync(configPath, 'utf-8'));\n const generated = JSON.parse(adapter.generate(result.mcpServers.scanned));\n existing.mcpServers = { ...(existing.mcpServers ?? {}), ...generated.mcpServers };\n configContent = JSON.stringify(existing, null, 2);\n } catch {\n configContent = adapter.generate(result.mcpServers.scanned);\n }\n } else {\n configContent = adapter.generate(result.mcpServers.scanned);\n }\n\n result.mcpServers.generated.push({\n filePath: configPath,\n content: sanitize(configContent),\n });\n }\n\n // 2. Convert workflows to target format\n result.workflows.scanned = scan.workflows;\n if (scan.workflows.length > 0) {\n result.workflows.generated = this.workflowSyncer.convertAll(scan.workflows, target);\n }\n\n // 3. Rules sync\n try {\n const rules = await this.rulesSyncer.scanRules();\n result.rules.scanned = rules.length;\n if (rules.length > 0) {\n const deduped = this.rulesSyncer.deduplicateRules(rules);\n const ruleSource = this.agentToRuleSource(target);\n if (ruleSource) {\n const files = this.rulesSyncer.generateForTarget(deduped, ruleSource);\n result.rules.generated = files.length;\n }\n }\n } catch {\n // Rules may not exist\n }\n\n // 4. Skills sync (no format conversion, just copy folders)\n result.skills.scanned = itemFilter\n ? scan.skills.filter(sk => itemFilter.has(sk.name.toLowerCase()))\n : scan.skills;\n result.skills.conflicts = scan.skillConflicts;\n\n return result;\n }\n\n // ---- Private helpers ----\n\n /** Skills directories per agent */\n private static SKILLS_DIRS: Record<AgentTarget, string[]> = {\n codex: ['.codex/skills', '.agents/skills'],\n cursor: ['.cursor/skills', '.cursor/skills-cursor'],\n windsurf: ['.windsurf/skills'],\n 'claude-code': ['.claude/skills'],\n copilot: ['.github/skills', '.copilot/skills'],\n antigravity: ['.agent/skills', '.gemini/skills', '.gemini/antigravity/skills'],\n kiro: ['.kiro/skills'],\n opencode: ['.opencode/skills'],\n trae: ['.trae/skills'],\n };\n\n /** Get the target skills directory for an agent (null if agent has no skills support) */\n private getTargetSkillsDir(target: AgentTarget): string | null {\n const dirs = WorkspaceSyncEngine.SKILLS_DIRS[target];\n if (!dirs || dirs.length === 0) return null;\n return join(this.projectRoot, dirs[0]);\n }\n\n /**\n * Scan all agent skills directories and collect unique skills.\n */\n private scanSkills(): { skills: SkillEntry[]; conflicts: SkillConflict[] } {\n const skills: SkillEntry[] = [];\n const conflicts: SkillConflict[] = [];\n const seen = new Map<string, SkillEntry>();\n const home = homedir();\n\n for (const [agent, dirs] of Object.entries(WorkspaceSyncEngine.SKILLS_DIRS)) {\n for (const dir of dirs) {\n // Check project-level and global\n const paths = [\n join(this.projectRoot, dir),\n join(home, dir),\n ];\n\n for (const skillsRoot of paths) {\n if (!existsSync(skillsRoot)) continue;\n\n try {\n const entries = readdirSync(skillsRoot, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const skillMd = join(skillsRoot, entry.name, 'SKILL.md');\n if (!existsSync(skillMd)) continue;\n\n // Parse description from frontmatter\n let description = '';\n try {\n const content = readFileSync(skillMd, 'utf-8');\n const match = content.match(/^---[\\s\\S]*?description:\\s*[\"']?(.+?)[\"']?\\s*$/m);\n if (match) description = match[1];\n } catch { /* skip */ }\n\n const newEntry: SkillEntry = {\n name: entry.name,\n description,\n sourcePath: join(skillsRoot, entry.name),\n sourceAgent: agent as AgentTarget,\n };\n\n const existing = seen.get(entry.name);\n if (existing) {\n // Conflict: same name from different agent\n if (existing.sourceAgent !== agent) {\n conflicts.push({\n name: entry.name,\n kept: existing,\n skipped: newEntry,\n });\n }\n continue;\n }\n\n seen.set(entry.name, newEntry);\n skills.push(newEntry);\n }\n } catch { /* skip unreadable dirs */ }\n }\n }\n }\n\n return { skills, conflicts };\n }\n\n /**\n * Copy skills to a target agent's skills directory.\n * Returns list of copied skill names.\n */\n copySkills(skills: SkillEntry[], target: AgentTarget): { copied: string[]; skipped: string[] } {\n const targetDir = this.getTargetSkillsDir(target);\n const copied: string[] = [];\n const skipped: string[] = [];\n\n // Agent has no skills directory support (e.g. copilot)\n if (!targetDir) {\n return { copied, skipped };\n }\n\n for (const skill of skills) {\n // Don't copy a skill back to its own agent\n if (skill.sourceAgent === target) continue;\n\n const dest = join(targetDir, skill.name);\n if (existsSync(dest)) {\n skipped.push(`${skill.name} (already exists in ${target})`);\n continue;\n }\n\n try {\n mkdirSync(targetDir, { recursive: true });\n cpSync(skill.sourcePath, dest, { recursive: true });\n copied.push(skill.name);\n } catch { /* skip on error */ }\n }\n\n return { copied, skipped };\n }\n\n private scanWorkflows(): WorkflowEntry[] {\n const workflows: WorkflowEntry[] = [];\n const wfDir = join(this.projectRoot, '.windsurf', 'workflows');\n\n if (!existsSync(wfDir)) return workflows;\n\n try {\n const files = readdirSync(wfDir).filter((f) => f.endsWith('.md'));\n for (const file of files) {\n try {\n const content = readFileSync(join(wfDir, file), 'utf-8');\n workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file, content));\n } catch {\n // Skip unreadable files\n }\n }\n } catch {\n // Directory read error\n }\n\n return workflows;\n }\n\n /**\n * Apply migration results to disk with backup and rollback.\n *\n * Safety features:\n * - Backs up every existing file before overwriting\n * - Atomic writes (temp → rename)\n * - Auto-rollback on any failure\n * - Returns backup paths for manual rollback if needed\n */\n async apply(target: AgentTarget, items?: string[]): Promise<ApplyResult & { migrationSummary: string }> {\n const syncResult = await this.migrate(target, items);\n const applier = new WorkspaceSyncApplier();\n\n // Collect all files to write\n const filesToWrite = [\n ...syncResult.mcpServers.generated,\n ...syncResult.workflows.generated,\n ];\n\n const applyResult = await applier.apply(filesToWrite);\n\n // Copy skills (no format conversion needed)\n let skillResult = { copied: [] as string[], skipped: [] as string[] };\n if (syncResult.skills.scanned.length > 0) {\n skillResult = this.copySkills(syncResult.skills.scanned, target);\n }\n\n // Build summary\n const lines: string[] = [];\n if (applyResult.success) {\n lines.push(`✅ Applied ${applyResult.filesWritten.length} file(s) for ${target}`);\n for (const f of applyResult.filesWritten) {\n lines.push(` → ${f}`);\n }\n if (skillResult.copied.length > 0) {\n lines.push(`\\n🧩 Copied ${skillResult.copied.length} skill(s):`);\n for (const sk of skillResult.copied) {\n lines.push(` → ${sk}`);\n }\n }\n if (skillResult.skipped.length > 0) {\n lines.push(`\\n⏭️ Skipped ${skillResult.skipped.length} skill(s):`);\n for (const sk of skillResult.skipped) {\n lines.push(` → ${sk}`);\n }\n }\n if (syncResult.skills.conflicts.length > 0) {\n lines.push(`\\n⚠️ Name conflicts (${syncResult.skills.conflicts.length}):`);\n for (const c of syncResult.skills.conflicts) {\n lines.push(` → \"${c.name}\": kept ${c.kept.sourceAgent}, skipped ${c.skipped.sourceAgent}`);\n }\n }\n if (applyResult.backups.length > 0) {\n lines.push(`\\n📦 Backups created (${applyResult.backups.length}):`);\n for (const b of applyResult.backups) {\n lines.push(` ${b.originalPath} → ${b.backupPath}`);\n }\n }\n // Clean up backups after successful apply\n applier.cleanBackups(applyResult.backups);\n } else {\n lines.push(`❌ Apply failed for ${target}`);\n for (const e of applyResult.errors) {\n lines.push(` Error: ${e}`);\n }\n if (applyResult.backups.length > 0) {\n lines.push(`\\n🔄 Rolled back ${applyResult.backups.length} file(s)`);\n }\n }\n\n return {\n ...applyResult,\n migrationSummary: lines.join('\\n'),\n };\n }\n\n // ---- Private helpers ----\n\n private agentToRuleSource(target: AgentTarget): RuleSource | null {\n const map: Record<AgentTarget, RuleSource> = {\n cursor: 'cursor',\n 'claude-code': 'claude-code',\n codex: 'codex',\n windsurf: 'windsurf',\n copilot: 'copilot',\n antigravity: 'antigravity',\n kiro: 'kiro',\n opencode: 'codex',\n trae: 'trae',\n };\n return map[target] ?? null;\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Windsurf MCP config adapter.\n * Format: JSON file at ~/.codeium/windsurf/mcp_config.json\n *\n * Supports two transport modes:\n * 1. stdio: { command, args, env? }\n * 2. HTTP: { serverUrl, headers? }\n *\n * Also handles: disabled, disabledTools, env: null\n */\nexport class WindsurfMCPAdapter implements MCPConfigAdapter {\n readonly source = 'windsurf' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcpServers ?? config.mcp_servers ?? {};\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\n const result: MCPServerEntry = {\n name,\n command: entry.command ?? '',\n args: entry.args ?? [],\n };\n\n // HTTP transport: Windsurf uses \"serverUrl\" (not \"url\")\n if (entry.serverUrl) {\n result.url = entry.serverUrl;\n } else if (entry.url) {\n result.url = entry.url;\n }\n\n // Headers (for HTTP transport)\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\n result.headers = entry.headers;\n }\n\n // Env (can be null in Windsurf)\n if (entry.env && typeof entry.env === 'object' && Object.keys(entry.env).length > 0) {\n result.env = entry.env;\n }\n\n // Disabled flag\n if (entry.disabled === true) {\n result.disabled = true;\n }\n\n return result;\n });\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n\n if (s.url) {\n // HTTP transport — Windsurf uses \"serverUrl\"\n entry.serverUrl = s.url;\n if (s.headers && Object.keys(s.headers).length > 0) {\n entry.headers = s.headers;\n }\n } else {\n // stdio transport\n entry.command = s.command;\n entry.args = s.args;\n }\n\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n\n if (s.disabled === true) {\n entry.disabled = true;\n }\n\n mcpServers[s.name] = entry;\n }\n return JSON.stringify({ mcpServers }, null, 2);\n }\n\n getConfigPath(_projectRoot?: string): string {\n return join(homedir(), '.codeium', 'windsurf', 'mcp_config.json');\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Cursor MCP config adapter.\n * Format: JSON file at ~/.cursor/mcp.json or .cursor/mcp.json (project-level)\n * Structure: { mcpServers: { [name]: { command, args, env?, url? } } }\n */\nexport class CursorMCPAdapter implements MCPConfigAdapter {\n readonly source = 'cursor' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcpServers ?? {};\n return Object.entries(servers).map(([name, entry]: [string, any]) => ({\n name,\n command: entry.command ?? '',\n args: entry.args ?? [],\n ...(entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\n ...(entry.url ? { url: entry.url } : {}),\n }));\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n if (s.url) {\n entry.url = s.url;\n } else {\n entry.command = s.command;\n entry.args = s.args;\n }\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n mcpServers[s.name] = entry;\n }\n return JSON.stringify({ mcpServers }, null, 2);\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n return join(projectRoot, '.cursor', 'mcp.json');\n }\n return join(homedir(), '.cursor', 'mcp.json');\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Codex MCP config adapter.\n * Format: TOML file at ~/.codex/config.toml or .codex/config.toml (project-level)\n *\n * Structure:\n * [mcp_servers.<name>]\n * command = \"npx\"\n * args = [\"-y\", \"memorix-mcp\"]\n * url = \"https://...\" # for HTTP servers\n *\n * [mcp_servers.<name>.env]\n * KEY = \"value\"\n *\n * We implement a lightweight TOML parser (no external deps) sufficient\n * for MCP server config blocks. This avoids adding a TOML dependency.\n */\nexport class CodexMCPAdapter implements MCPConfigAdapter {\n readonly source = 'codex' as const;\n\n parse(content: string): MCPServerEntry[] {\n if (!content.trim()) return [];\n\n const servers: MCPServerEntry[] = [];\n const lines = content.split('\\n');\n\n let currentServer: string | null = null;\n let isEnvBlock = false;\n const serverMap = new Map<\n string,\n { command: string; args: string[]; env: Record<string, string>; url?: string; enabled?: boolean }\n >();\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n\n // Skip comments and empty lines\n if (!line || line.startsWith('#')) continue;\n\n // Match [mcp_servers.<name>.env]\n const envMatch = line.match(/^\\[mcp_servers\\.([^.\\]]+)\\.env\\]$/);\n if (envMatch) {\n currentServer = envMatch[1];\n isEnvBlock = true;\n if (!serverMap.has(currentServer)) {\n serverMap.set(currentServer, { command: '', args: [], env: {} });\n }\n continue;\n }\n\n // Match [mcp_servers.<name>]\n const serverMatch = line.match(/^\\[mcp_servers\\.([^.\\]]+)\\]$/);\n if (serverMatch) {\n currentServer = serverMatch[1];\n isEnvBlock = false;\n if (!serverMap.has(currentServer)) {\n serverMap.set(currentServer, { command: '', args: [], env: {} });\n }\n continue;\n }\n\n // Any other section header resets context\n if (line.startsWith('[')) {\n currentServer = null;\n isEnvBlock = false;\n continue;\n }\n\n // Parse key = value within current server block\n if (currentServer) {\n const kvMatch = line.match(/^(\\w+)\\s*=\\s*(.+)$/);\n if (!kvMatch) continue;\n\n const key = kvMatch[1];\n const rawValue = kvMatch[2].trim();\n const entry = serverMap.get(currentServer)!;\n\n if (isEnvBlock) {\n entry.env[key] = this.parseTomlString(rawValue);\n } else if (key === 'command') {\n entry.command = this.parseTomlString(rawValue);\n } else if (key === 'args') {\n entry.args = this.parseTomlArray(rawValue);\n } else if (key === 'url') {\n entry.url = this.parseTomlString(rawValue);\n } else if (key === 'enabled') {\n entry.enabled = rawValue === 'true';\n }\n }\n }\n\n for (const [name, entry] of serverMap) {\n servers.push({\n name,\n command: entry.command,\n args: entry.args,\n ...(Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\n ...(entry.url ? { url: entry.url } : {}),\n });\n }\n\n return servers;\n }\n\n generate(servers: MCPServerEntry[]): string {\n const blocks: string[] = [];\n\n for (const s of servers) {\n const lines: string[] = [];\n lines.push(`[mcp_servers.${s.name}]`);\n\n if (s.url) {\n lines.push(`url = ${this.toTomlString(s.url)}`);\n } else {\n lines.push(`command = ${this.toTomlString(s.command)}`);\n lines.push(`args = [${s.args.map((a) => this.toTomlString(a)).join(', ')}]`);\n }\n\n if (s.env && Object.keys(s.env).length > 0) {\n lines.push('');\n lines.push(`[mcp_servers.${s.name}.env]`);\n for (const [key, value] of Object.entries(s.env)) {\n lines.push(`${key} = ${this.toTomlString(value)}`);\n }\n }\n\n blocks.push(lines.join('\\n'));\n }\n\n return blocks.join('\\n\\n') + '\\n';\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n return join(projectRoot, '.codex', 'config.toml');\n }\n return join(homedir(), '.codex', 'config.toml');\n }\n\n // ---- TOML helpers ----\n\n private parseTomlString(raw: string): string {\n const trimmed = raw.trim();\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n }\n\n private parseTomlArray(raw: string): string[] {\n const trimmed = raw.trim();\n if (!trimmed.startsWith('[') || !trimmed.endsWith(']')) return [];\n const inner = trimmed.slice(1, -1);\n const result: string[] = [];\n // Simple CSV parse respecting quotes\n let current = '';\n let inQuote = false;\n let quoteChar = '';\n for (const ch of inner) {\n if (inQuote) {\n if (ch === quoteChar) {\n inQuote = false;\n } else {\n current += ch;\n }\n } else if (ch === '\"' || ch === \"'\") {\n inQuote = true;\n quoteChar = ch;\n } else if (ch === ',') {\n const val = current.trim();\n if (val) result.push(val);\n current = '';\n } else {\n current += ch;\n }\n }\n const last = current.trim();\n if (last) result.push(last);\n return result;\n }\n\n private toTomlString(value: string): string {\n return `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Claude Code MCP config adapter.\n * Format: JSON file at ~/.claude.json or project-level .claude/settings.json\n * Structure: { mcpServers: { [name]: { command, args, env?, url? } } }\n */\nexport class ClaudeCodeMCPAdapter implements MCPConfigAdapter {\n readonly source = 'claude-code' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcpServers ?? {};\n return Object.entries(servers).map(([name, entry]: [string, any]) => ({\n name,\n command: entry.command ?? '',\n args: entry.args ?? [],\n ...(entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\n ...(entry.url ? { url: entry.url } : {}),\n }));\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n if (s.url) {\n entry.url = s.url;\n } else {\n entry.command = s.command;\n entry.args = s.args;\n }\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n mcpServers[s.name] = entry;\n }\n return JSON.stringify({ mcpServers }, null, 2);\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n return join(projectRoot, '.claude', 'settings.json');\n }\n return join(homedir(), '.claude.json');\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * VS Code Copilot MCP config adapter.\n *\n * Supports two config locations / formats:\n *\n * 1. Workspace-level (preferred, new):\n * Path: .vscode/mcp.json\n * Format: { \"servers\": { [name]: { command, args, env?, url? } } }\n *\n * 2. Global (legacy, still scanned):\n * Path: %APPDATA%/Code/User/settings.json\n * Format: { \"mcp\": { \"servers\": { [name]: { command, args, env? } } } }\n *\n * parse() auto-detects which format is provided.\n * generate() always outputs the new .vscode/mcp.json format.\n * getConfigPath(projectRoot) returns workspace path; getConfigPath() returns global path.\n */\nexport class CopilotMCPAdapter implements MCPConfigAdapter {\n readonly source = 'copilot' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n\n // Auto-detect format:\n // 1. mcp.json format: { \"servers\": { ... } }\n // 2. settings.json format: { \"mcp\": { \"servers\": { ... } } }\n const servers = config?.servers ?? config?.mcp?.servers ?? {};\n\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\n const result: MCPServerEntry = {\n name,\n command: entry.command ?? '',\n args: entry.args ?? [],\n };\n\n if (entry.type) {\n // VS Code mcp.json supports \"type\" field (e.g., \"http\", \"stdio\")\n // Map to url for HTTP types\n if ((entry.type === 'http' || entry.type === 'sse') && entry.url) {\n result.url = entry.url;\n }\n } else if (entry.url) {\n result.url = entry.url;\n }\n\n if (entry.env && typeof entry.env === 'object' && Object.keys(entry.env).length > 0) {\n result.env = entry.env;\n }\n\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\n result.headers = entry.headers;\n }\n\n return result;\n });\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n if (s.url) {\n entry.type = 'http';\n entry.url = s.url;\n if (s.headers && Object.keys(s.headers).length > 0) {\n entry.headers = s.headers;\n }\n } else {\n entry.command = s.command;\n entry.args = s.args;\n }\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n mcpServers[s.name] = entry;\n }\n\n // Output the new .vscode/mcp.json format: { \"servers\": { ... } }\n return JSON.stringify({ servers: mcpServers }, null, 2);\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n // Workspace-level: .vscode/mcp.json (new official format)\n return join(projectRoot, '.vscode', 'mcp.json');\n }\n // Global: VS Code user settings path (legacy, for scan fallback)\n const home = homedir();\n if (process.platform === 'win32') {\n return join(home, 'AppData', 'Roaming', 'Code', 'User', 'settings.json');\n } else if (process.platform === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Code', 'User', 'settings.json');\n } else {\n return join(home, '.config', 'Code', 'User', 'settings.json');\n }\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\r\nimport { homedir } from 'node:os';\r\nimport { join } from 'node:path';\r\n\r\n/**\r\n * Antigravity IDE MCP Configuration Adapter.\r\n *\r\n * Antigravity uses two JSON config files for MCP servers:\r\n * 1. Global MCP: ~/.gemini/antigravity/mcp_config.json\r\n * Format: { \"mcpServers\": { \"name\": { command, args, env? } } }\r\n *\r\n * 2. Global settings: ~/.gemini/settings.json\r\n * Format: { \"mcpServers\": { \"name\": { command, args, env? } } }\r\n *\r\n * The mcp_config.json format is the primary config, same JSON structure\r\n * as Windsurf but at a different path. Also supports HTTP transport via url.\r\n *\r\n * Source: Antigravity official documentation (https://antigravity.google/docs/agent/mcp)\r\n * Verified on local machine: C:\\Users\\<USER>\\.gemini\\antigravity\\mcp_config.json\r\n */\r\nexport class AntigravityMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'antigravity' as const;\r\n\r\n parse(content: string): MCPServerEntry[] {\r\n try {\r\n const config = JSON.parse(content);\r\n const servers = config.mcpServers ?? config.mcp_servers ?? {};\r\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\r\n const result: MCPServerEntry = {\r\n name,\r\n command: entry.command ?? '',\r\n args: entry.args ?? [],\r\n };\r\n\r\n // HTTP transport\r\n if (entry.serverUrl) {\r\n result.url = entry.serverUrl;\r\n } else if (entry.url) {\r\n result.url = entry.url;\r\n }\r\n\r\n // Headers (for HTTP transport)\r\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\r\n result.headers = entry.headers;\r\n }\r\n\r\n // Env\r\n if (entry.env && typeof entry.env === 'object' && Object.keys(entry.env).length > 0) {\r\n result.env = entry.env;\r\n }\r\n\r\n // Disabled flag\r\n if (entry.disabled === true) {\r\n result.disabled = true;\r\n }\r\n\r\n return result;\r\n });\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n generate(servers: MCPServerEntry[]): string {\r\n const mcpServers: Record<string, any> = {};\r\n for (const s of servers) {\r\n const entry: Record<string, any> = {};\r\n\r\n if (s.url) {\r\n // HTTP transport\r\n entry.url = s.url;\r\n if (s.headers && Object.keys(s.headers).length > 0) {\r\n entry.headers = s.headers;\r\n }\r\n } else {\r\n // stdio transport\r\n entry.command = s.command;\r\n entry.args = s.args;\r\n }\r\n\r\n if (s.env && Object.keys(s.env).length > 0) {\r\n entry.env = s.env;\r\n }\r\n\r\n if (s.disabled === true) {\r\n entry.disabled = true;\r\n }\r\n\r\n mcpServers[s.name] = entry;\r\n }\r\n return JSON.stringify({ mcpServers }, null, 2);\r\n }\r\n\r\n getConfigPath(projectRoot?: string): string {\r\n if (projectRoot) {\r\n // Project-level: .gemini/settings.json (shared with hooks)\r\n return join(projectRoot, '.gemini', 'settings.json');\r\n }\r\n // Global: ~/.gemini/settings.json\r\n return join(homedir(), '.gemini', 'settings.json');\r\n }\r\n}\r\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\r\nimport { homedir } from 'node:os';\r\nimport { join } from 'node:path';\r\n\r\n/**\r\n * Kiro MCP config adapter.\r\n * Format: JSON file at .kiro/settings/mcp.json (project-level)\r\n * or ~/.kiro/settings/mcp.json (user-level)\r\n * Structure: { mcpServers: { ... }, powers?: { mcpServers: { ... } } }\r\n *\r\n * Kiro stores user-added servers in `mcpServers` and power-installed\r\n * servers (context7, figma, postman, supabase etc.) in `powers.mcpServers`.\r\n * Both sections use the same entry format.\r\n *\r\n * Source: Kiro official MCP documentation.\r\n */\r\nexport class KiroMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'kiro' as const;\r\n\r\n parse(content: string): MCPServerEntry[] {\r\n try {\r\n const config = JSON.parse(content);\r\n // Merge top-level mcpServers and powers.mcpServers (dedup by name)\r\n const topLevel = config.mcpServers ?? {};\r\n const powers = config.powers?.mcpServers ?? {};\r\n const merged = { ...powers, ...topLevel };\r\n return Object.entries(merged).map(([name, entry]: [string, any]) => ({\r\n name,\r\n command: entry.command ?? '',\r\n args: entry.args ?? [],\r\n ...(entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\r\n ...(entry.url ? { url: entry.url } : {}),\r\n ...(entry.disabled === true ? { disabled: true } : {}),\r\n }));\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n generate(servers: MCPServerEntry[]): string {\r\n const mcpServers: Record<string, any> = {};\r\n for (const s of servers) {\r\n const entry: Record<string, any> = {};\r\n if (s.url) {\r\n entry.url = s.url;\r\n } else {\r\n entry.command = s.command;\r\n entry.args = s.args;\r\n }\r\n if (s.env && Object.keys(s.env).length > 0) {\r\n entry.env = s.env;\r\n }\r\n mcpServers[s.name] = entry;\r\n }\r\n return JSON.stringify({ mcpServers }, null, 2);\r\n }\r\n\r\n getConfigPath(projectRoot?: string): string {\r\n if (projectRoot) {\r\n return join(projectRoot, '.kiro', 'settings', 'mcp.json');\r\n }\r\n return join(homedir(), '.kiro', 'settings', 'mcp.json');\r\n }\r\n}\r\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * OpenCode MCP Configuration Adapter.\n *\n * OpenCode uses JSON config files for MCP servers:\n * 1. Project-level: opencode.json in project root\n * 2. Global: ~/.config/opencode/opencode.json\n *\n * Format:\n * {\n * \"$schema\": \"https://opencode.ai/config.json\",\n * \"mcp\": {\n * \"name\": {\n * \"type\": \"local\",\n * \"command\": [\"memorix\", \"serve\"],\n * \"environment\": { \"KEY\": \"value\" },\n * \"enabled\": true\n * }\n * }\n * }\n *\n * Remote (HTTP) servers:\n * {\n * \"mcp\": {\n * \"name\": {\n * \"type\": \"remote\",\n * \"url\": \"https://...\",\n * \"headers\": { \"Authorization\": \"Bearer ...\" }\n * }\n * }\n * }\n *\n * Source: https://opencode.ai/docs/mcp-servers/\n */\nexport class OpenCodeMCPAdapter implements MCPConfigAdapter {\n readonly source = 'opencode' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcp ?? {};\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\n const result: MCPServerEntry = {\n name,\n command: '',\n args: [],\n };\n\n if (entry.type === 'remote' && entry.url) {\n // HTTP transport\n result.url = entry.url;\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\n result.headers = entry.headers;\n }\n } else {\n // Local (stdio) transport — command is an array in OpenCode\n if (Array.isArray(entry.command) && entry.command.length > 0) {\n result.command = entry.command[0];\n result.args = entry.command.slice(1);\n } else if (typeof entry.command === 'string') {\n result.command = entry.command;\n }\n }\n\n // Environment variables (OpenCode uses \"environment\" not \"env\")\n const env = entry.environment ?? entry.env;\n if (env && typeof env === 'object' && Object.keys(env).length > 0) {\n result.env = env;\n }\n\n // Disabled flag\n if (entry.enabled === false) {\n result.disabled = true;\n }\n\n return result;\n });\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcp: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n\n if (s.url) {\n // HTTP transport\n entry.type = 'remote';\n entry.url = s.url;\n if (s.headers && Object.keys(s.headers).length > 0) {\n entry.headers = s.headers;\n }\n } else {\n // stdio transport — OpenCode uses command as array\n entry.type = 'local';\n entry.command = [s.command, ...s.args];\n }\n\n if (s.env && Object.keys(s.env).length > 0) {\n entry.environment = s.env;\n }\n\n if (s.disabled === true) {\n entry.enabled = false;\n }\n\n mcp[s.name] = entry;\n }\n return JSON.stringify({ $schema: 'https://opencode.ai/config.json', mcp }, null, 2);\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n return join(projectRoot, 'opencode.json');\n }\n return join(homedir(), '.config', 'opencode', 'opencode.json');\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\n/**\n * Trae IDE MCP Configuration Adapter.\n *\n * Trae stores MCP config at the user level:\n * %APPDATA%/Trae/User/mcp.json (Windows)\n * ~/Library/Application Support/Trae/User/mcp.json (macOS)\n * ~/.config/Trae/User/mcp.json (Linux)\n *\n * Format (OBJECT-keyed, same as Cursor):\n * {\n * \"mcpServers\": {\n * \"memorix\": {\n * \"command\": \"memorix\",\n * \"args\": [\"serve\"],\n * \"env\": { \"KEY\": \"value\" }\n * }\n * }\n * }\n *\n * SSE transport:\n * {\n * \"mcpServers\": {\n * \"remote\": {\n * \"url\": \"https://...\",\n * \"type\": \"sse\"\n * }\n * }\n * }\n *\n * Source: https://docs.trae.ai/ide/model-context-protocol\n */\nexport class TraeMCPAdapter implements MCPConfigAdapter {\n readonly source = 'trae' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcpServers;\n\n if (!servers || typeof servers !== 'object') return [];\n\n // Object-keyed format: { \"mcpServers\": { \"name\": { ... } } }\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\n const result: MCPServerEntry = {\n name,\n command: '',\n args: [],\n };\n\n if (typeof entry.command === 'string') {\n result.command = entry.command;\n }\n\n if (Array.isArray(entry.args)) {\n result.args = entry.args;\n }\n\n // SSE/HTTP transport\n if (entry.url) {\n result.url = entry.url;\n }\n\n // Environment variables\n if (entry.env && typeof entry.env === 'object' && Object.keys(entry.env).length > 0) {\n result.env = entry.env;\n }\n\n // Headers (for HTTP transport)\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\n result.headers = entry.headers;\n }\n\n // Disabled flag\n if (entry.disabled === true) {\n result.disabled = true;\n }\n\n return result;\n });\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n\n for (const s of servers) {\n const entry: Record<string, any> = {};\n\n if (s.url) {\n // SSE/HTTP transport\n entry.url = s.url;\n if (s.headers && Object.keys(s.headers).length > 0) {\n entry.headers = s.headers;\n }\n } else {\n // stdio transport\n entry.command = s.command;\n if (s.args && s.args.length > 0) {\n entry.args = s.args;\n }\n }\n\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n\n if (s.disabled === true) {\n entry.disabled = true;\n }\n\n mcpServers[s.name] = entry;\n }\n\n return JSON.stringify({ mcpServers }, null, 2);\n }\n\n getConfigPath(_projectRoot?: string): string {\n const home = homedir();\n // Trae stores user-level MCP config in AppData (Windows) / Application Support (macOS) / .config (Linux)\n if (process.platform === 'win32') {\n return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'Trae', 'User', 'mcp.json');\n }\n if (process.platform === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Trae', 'User', 'mcp.json');\n }\n return join(home, '.config', 'Trae', 'User', 'mcp.json');\n }\n}\n","import matter from 'gray-matter';\nimport type { AgentTarget, WorkflowEntry } from '../types.js';\n\n/**\n * WorkflowSyncer — converts workflows between agent formats.\n *\n * Supported conversions:\n * Windsurf .windsurf/workflows/*.md → Codex SKILL.md\n * Windsurf .windsurf/workflows/*.md → Cursor .cursor/rules/*.mdc\n * Windsurf .windsurf/workflows/*.md → Claude Code CLAUDE.md section\n */\nexport class WorkflowSyncer {\n /**\n * Parse a Windsurf workflow markdown file into a WorkflowEntry.\n */\n parseWindsurfWorkflow(fileName: string, raw: string): WorkflowEntry {\n const name = fileName.replace(/\\.md$/i, '');\n let description = '';\n let content = raw;\n\n try {\n const parsed = matter(raw);\n description = parsed.data?.description ?? '';\n content = parsed.content.trim();\n } catch {\n // No frontmatter — use raw content\n }\n\n return {\n name,\n description,\n content,\n source: 'windsurf',\n filePath: `.windsurf/workflows/${fileName}`,\n };\n }\n\n /**\n * Convert a workflow to Codex SKILL.md format.\n */\n toCodexSkill(wf: WorkflowEntry): { filePath: string; content: string } {\n const safeName = this.sanitizeName(wf.name);\n const fm: Record<string, string> = { name: safeName };\n if (wf.description) {\n fm.description = wf.description;\n }\n const content = matter.stringify(wf.content, fm);\n return {\n filePath: `.agents/skills/${safeName}/SKILL.md`,\n content,\n };\n }\n\n /**\n * Convert a workflow to Cursor .mdc rule format.\n */\n toCursorRule(wf: WorkflowEntry): { filePath: string; content: string } {\n const safeName = this.sanitizeName(wf.name);\n const fm: Record<string, string> = {};\n if (wf.description) {\n fm.description = wf.description;\n }\n fm.globs = '';\n fm.alwaysApply = 'false';\n const content = matter.stringify(wf.content, fm);\n return {\n filePath: `.cursor/rules/${safeName}.mdc`,\n content,\n };\n }\n\n /**\n * Convert a workflow to a CLAUDE.md section string.\n */\n toClaudeSection(wf: WorkflowEntry): string {\n const lines: string[] = [];\n lines.push(`## Workflow: ${wf.name}`);\n if (wf.description) {\n lines.push('');\n lines.push(`> ${wf.description}`);\n }\n lines.push('');\n lines.push(wf.content);\n return lines.join('\\n');\n }\n\n /**\n * Convert all workflows to the target agent format.\n * Returns an array of { filePath, content } for each generated file.\n */\n convertAll(\n workflows: WorkflowEntry[],\n target: AgentTarget,\n ): { filePath: string; content: string }[] {\n if (target === 'windsurf') {\n // No conversion needed — already in Windsurf format\n return [];\n }\n\n if (target === 'codex') {\n return workflows.map((wf) => this.toCodexSkill(wf));\n }\n\n if (target === 'cursor') {\n return workflows.map((wf) => this.toCursorRule(wf));\n }\n\n if (target === 'claude-code') {\n // Merge all workflows into a single CLAUDE.md\n const sections = workflows.map((wf) => this.toClaudeSection(wf));\n return [\n {\n filePath: 'CLAUDE.md',\n content: sections.join('\\n\\n'),\n },\n ];\n }\n\n return [];\n }\n\n // ---- Helpers ----\n\n private sanitizeName(name: string): string {\n return name\n .replace(/[^a-zA-Z0-9_-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n || 'workflow';\n }\n}\n","/**\n * Sanitizer — mask sensitive values (tokens, keys, passwords) in output.\n *\n * Patterns detected:\n * - API keys / tokens (github_pat_*, ctx7sk-*, sk-*, ghp_*, ghu_*, etc.)\n * - Generic key=value where key contains \"token\", \"key\", \"secret\", \"password\"\n * - Bearer tokens\n */\n\nconst SENSITIVE_PATTERNS: { pattern: RegExp; replacement: string }[] = [\n // GitHub PAT (classic & fine-grained)\n { pattern: /ghp_[A-Za-z0-9_]{36,}/g, replacement: 'ghp_***' },\n { pattern: /github_pat_[A-Za-z0-9_]{60,}/g, replacement: 'github_pat_***' },\n { pattern: /ghu_[A-Za-z0-9_]{36,}/g, replacement: 'ghu_***' },\n { pattern: /ghs_[A-Za-z0-9_]{36,}/g, replacement: 'ghs_***' },\n // OpenAI / Anthropic style keys\n { pattern: /sk-[A-Za-z0-9_-]{20,}/g, replacement: 'sk-***' },\n // Context7 keys\n { pattern: /ctx7sk-[A-Za-z0-9-]{20,}/g, replacement: 'ctx7sk-***' },\n // Generic long hex/base64 tokens (32+ chars) in quoted values\n { pattern: /\"([A-Za-z0-9_-]{40,})\"/g, replacement: '\"***\"' },\n];\n\nconst SENSITIVE_KEY_PATTERN = /(?:token|key|secret|password|credential|auth)/i;\n\n/**\n * Mask sensitive values in a string.\n */\nexport function sanitize(input: string): string {\n let result = input;\n\n // Apply known token patterns\n for (const { pattern, replacement } of SENSITIVE_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n result = result.replace(pattern, replacement);\n }\n\n return result;\n}\n\n/**\n * Mask sensitive values in MCPServerEntry env/headers objects.\n * Returns a new object with masked values.\n */\nexport function sanitizeRecord(\n record: Record<string, string> | undefined | null,\n): Record<string, string> | undefined {\n if (!record) return undefined;\n\n const masked: Record<string, string> = {};\n for (const [key, value] of Object.entries(record)) {\n if (SENSITIVE_KEY_PATTERN.test(key)) {\n masked[key] = '***';\n } else {\n masked[key] = value;\n }\n }\n return masked;\n}\n","/**\n * Workspace Sync Applier\n *\n * Writes generated workspace sync results to disk with safety features:\n * 1. Pre-flight validation (check writability)\n * 2. Backup existing files before overwrite\n * 3. Atomic write (write to temp, then rename)\n * 4. Rollback on failure\n *\n * Usage:\n * const applier = new WorkspaceSyncApplier();\n * const result = await applier.apply(syncResult);\n * if (!result.success) await applier.rollback(result.backups);\n */\n\nimport { existsSync, mkdirSync, copyFileSync, writeFileSync, unlinkSync, renameSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nexport interface ApplyResult {\n success: boolean;\n filesWritten: string[];\n backups: BackupEntry[];\n errors: string[];\n}\n\nexport interface BackupEntry {\n originalPath: string;\n backupPath: string;\n}\n\ninterface FileToWrite {\n filePath: string;\n content: string;\n}\n\n/**\n * Apply workspace sync results to disk with backup and rollback.\n */\nexport class WorkspaceSyncApplier {\n /**\n * Apply generated files to disk.\n *\n * Steps:\n * 1. Validate all target directories exist or can be created\n * 2. Backup existing files\n * 3. Write new files\n * 4. On any error → rollback all changes\n */\n async apply(files: FileToWrite[]): Promise<ApplyResult> {\n const result: ApplyResult = {\n success: false,\n filesWritten: [],\n backups: [],\n errors: [],\n };\n\n if (files.length === 0) {\n result.success = true;\n return result;\n }\n\n // Step 1: Pre-flight — ensure all directories exist\n for (const file of files) {\n try {\n const dir = dirname(file.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n } catch (err) {\n result.errors.push(`Cannot create directory for ${file.filePath}: ${err}`);\n return result;\n }\n }\n\n // Step 2: Backup existing files\n for (const file of files) {\n if (existsSync(file.filePath)) {\n try {\n const backupPath = file.filePath + `.backup-${Date.now()}`;\n copyFileSync(file.filePath, backupPath);\n result.backups.push({\n originalPath: file.filePath,\n backupPath,\n });\n } catch (err) {\n result.errors.push(`Cannot backup ${file.filePath}: ${err}`);\n return result;\n }\n }\n }\n\n // Step 3: Write new files\n for (const file of files) {\n try {\n // Write to temp file first, then rename (pseudo-atomic)\n const tempPath = file.filePath + `.tmp-${Date.now()}`;\n writeFileSync(tempPath, file.content, 'utf-8');\n renameSync(tempPath, file.filePath);\n result.filesWritten.push(file.filePath);\n } catch (err) {\n result.errors.push(`Cannot write ${file.filePath}: ${err}`);\n // Rollback everything written so far\n this.rollback(result.backups);\n return result;\n }\n }\n\n result.success = true;\n return result;\n }\n\n /**\n * Rollback applied changes by restoring backups.\n */\n rollback(backups: BackupEntry[]): { restored: number; errors: string[] } {\n const errors: string[] = [];\n let restored = 0;\n\n for (const backup of backups) {\n try {\n copyFileSync(backup.backupPath, backup.originalPath);\n restored++;\n } catch (err) {\n errors.push(`Cannot restore ${backup.originalPath} from ${backup.backupPath}: ${err}`);\n }\n }\n\n return { restored, errors };\n }\n\n /**\n * Clean up backup files after successful apply.\n */\n cleanBackups(backups: BackupEntry[]): void {\n for (const backup of backups) {\n try {\n if (existsSync(backup.backupPath)) {\n unlinkSync(backup.backupPath);\n }\n } catch {\n // Best-effort cleanup\n }\n }\n }\n}\n"],"mappings":"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","names":["path","projectDir","fs","path","projectDir","observations","nextId","join","homedir","cache","MAX_CACHE_SIZE","createHash","readFile","writeFile","mkdir","join","homedir","textHash","loadDiskCache","CACHE_FILE","cache","diskCacheDirty","CACHE_DIR","MAX_CACHE_SIZE","MAX_RETRIES","getEmbeddingMode","FastEmbedProvider","TransformersProvider","APIEmbeddingProvider","fs","path","os","DEFAULT_DATA_DIR","getLLMApiKey","getLLMProvider","getLLMModel","getLLMBaseUrl","provider","init_provider","init_provider","provider","resolveAliases","rerankResults","getAllObservations","getObservationCount","removeObservation","count","init_provider","projectDir","projectDir","access","existsSync","readFileSync","writeFileSync","mkdirSync","readdirSync","join","homedir","observations","projectDir","observations","nextId","projectDir","MAX_BATCH_SIZE","projectDir","count","OBSERVATION_ICONS","observations","nextId","fs","path","getCanonicalId","count","observations","nextId","getEmbeddingProvider","isImmune","agent","count","randomUUID","count","count","randomUUID","count","persistence_exports","readFile","writeFile","mkdir","renameSync","existsSync","dirname","init_persistence","unlinkSync","fs","path","os","projectDir","observations","basename","existsSync","readFileSync","os","path","id","name","basename","fs","path","createHash","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","fs","path","readFileSync","existsSync","mkdirSync","join","homedir","homedir","join","homedir","join","homedir","join","homedir","join","homedir","join","homedir","join","homedir","join","homedir","join","join","homedir","matter","existsSync","join","homedir","path","existsSync","readFileSync","mkdirSync","init_provider","migrateSubdirsToFlat","projectDir","getAllObservations","getAllAliasGroups","resolveObservations","getActiveSession","compressNarrative","suggestTopicKey","getRetentionSummary","getArchiveCandidates","rankByRelevance","archiveExpired","search","homedir","join","readFile","observations","lines","SkillsEngine","loadObservationsJson","path","promoteToMiniSkill","loadAllMiniSkills","deleteMiniSkill","formatMiniSkillsForInjection","findConsolidationCandidates","executeConsolidation","startSession","recordMiniSkillUsage","endSession","getSessionContext","listSessions","exportAsJson","exportAsMarkdown","importFromJson","exec","fileURLToPath","startDashboard","AgentRegistry","MessageBus","FileLockRegistry","TaskManager","TeamPersistence","getHookStatus","installHooks","detectInstalledAgents","access","deduplicateMemory","count"]}
|
|
1
|
+
{"version":3,"sources":["../node_modules/tsup/assets/esm_shims.js","../src/store/file-lock.ts","../src/store/persistence.ts","../src/types.ts","../src/config.ts","../src/embedding/fastembed-provider.ts","../src/embedding/transformers-provider.ts","../src/embedding/api-provider.ts","../src/embedding/provider.ts","../src/store/project-affinity.ts","../src/search/intent-detector.ts","../src/project/aliases.ts","../src/llm/provider.ts","../src/llm/quality.ts","../src/store/orama-store.ts","../src/compact/token-budget.ts","../src/memory/entity-extractor.ts","../src/memory/observations.ts","../src/llm/memory-manager.ts","../src/memory/session.ts","../src/memory/retention.ts","../src/skills/engine.ts","../src/skills/mini-skills.ts","../src/memory/consolidation.ts","../src/memory/export-import.ts","../src/dashboard/server.ts","../src/team/registry.ts","../src/team/messages.ts","../src/team/file-locks.ts","../src/team/tasks.ts","../src/team/persistence.ts","../src/hooks/installers/index.ts","../src/index.ts","../src/server.ts","../src/memory/graph.ts","../src/memory/auto-relations.ts","../src/compact/engine.ts","../src/compact/index-format.ts","../src/project/detector.ts","../src/rules/syncer.ts","../src/rules/adapters/cursor.ts","../src/rules/utils.ts","../src/rules/adapters/claude-code.ts","../src/rules/adapters/codex.ts","../src/rules/adapters/windsurf.ts","../src/rules/adapters/antigravity.ts","../src/rules/adapters/copilot.ts","../src/rules/adapters/kiro.ts","../src/rules/adapters/trae.ts","../src/workspace/engine.ts","../src/workspace/mcp-adapters/windsurf.ts","../src/workspace/mcp-adapters/cursor.ts","../src/workspace/mcp-adapters/codex.ts","../src/workspace/mcp-adapters/claude-code.ts","../src/workspace/mcp-adapters/copilot.ts","../src/workspace/mcp-adapters/antigravity.ts","../src/workspace/mcp-adapters/kiro.ts","../src/workspace/mcp-adapters/opencode.ts","../src/workspace/mcp-adapters/trae.ts","../src/workspace/workflow-sync.ts","../src/workspace/sanitizer.ts","../src/workspace/applier.ts"],"sourcesContent":["// Shim globals in esm bundle\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nconst getFilename = () => fileURLToPath(import.meta.url)\nconst getDirname = () => path.dirname(getFilename())\n\nexport const __dirname = /* @__PURE__ */ getDirname()\nexport const __filename = /* @__PURE__ */ getFilename()\n","/**\n * File Lock & Atomic Write Utilities\n *\n * Provides cross-process file locking using .lock files with atomic creation\n * (O_CREAT | O_EXCL), and atomic file writes via temp-file-then-rename.\n *\n * This prevents data corruption when multiple MCP server instances\n * (e.g., Cursor + Windsurf) write to the same project directory simultaneously.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\n\n/** Lock is considered stale after 10 seconds (process crash recovery) */\nconst LOCK_STALE_MS = 10_000;\n/** Retry interval when waiting for lock */\nconst RETRY_INTERVAL_MS = 50;\n/** Maximum retries before giving up (50ms × 60 = 3 seconds) */\nconst MAX_RETRIES = 60;\n\n/**\n * Acquire a lock file atomically.\n * Uses O_WRONLY | O_CREAT | O_EXCL — fails if file already exists.\n * Handles stale locks from crashed processes.\n */\nexport async function acquireLock(lockPath: string): Promise<void> {\n for (let i = 0; i < MAX_RETRIES; i++) {\n try {\n const fd = await fs.open(lockPath, 'wx');\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\n await fd.close();\n return;\n } catch (err: unknown) {\n const code = err instanceof Error && 'code' in err ? (err as NodeJS.ErrnoException).code : undefined;\n if (code === 'EEXIST' || code === 'EPERM') {\n // Lock exists — check if stale\n try {\n const stat = await fs.stat(lockPath);\n if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) {\n await fs.unlink(lockPath).catch(() => {});\n continue;\n }\n } catch {\n continue; // Lock disappeared — retry immediately\n }\n await new Promise(r => setTimeout(r, RETRY_INTERVAL_MS));\n } else {\n throw err;\n }\n }\n }\n // Last resort: force-remove stale lock and try once more\n await fs.unlink(lockPath).catch(() => {});\n try {\n const fd = await fs.open(lockPath, 'wx');\n await fd.writeFile(JSON.stringify({ pid: process.pid, time: Date.now() }));\n await fd.close();\n return;\n } catch {\n throw new Error(`Failed to acquire lock: ${lockPath} (timeout after ${MAX_RETRIES * RETRY_INTERVAL_MS}ms)`);\n }\n}\n\n/**\n * Release a lock file.\n */\nexport async function releaseLock(lockPath: string): Promise<void> {\n await fs.unlink(lockPath).catch(() => {});\n}\n\n/**\n * Execute a function while holding a project-level lock.\n * Ensures only one process writes to the project directory at a time.\n *\n * @param projectDir - The project data directory to lock\n * @param fn - The async function to execute while holding the lock\n * @returns The return value of fn\n */\nexport async function withFileLock<T>(projectDir: string, fn: () => Promise<T>): Promise<T> {\n const lockPath = path.join(projectDir, '.memorix.lock');\n await acquireLock(lockPath);\n try {\n return await fn();\n } finally {\n await releaseLock(lockPath);\n }\n}\n\n/**\n * Write a file atomically: write to .tmp, then rename.\n * Prevents partial writes from corrupting data files on crash.\n *\n * On most filesystems, rename() is atomic within the same directory,\n * so readers always see either the old complete file or the new complete file.\n */\nexport async function atomicWriteFile(filePath: string, data: string): Promise<void> {\n const tmpPath = filePath + `.tmp.${process.pid}`;\n await fs.writeFile(tmpPath, data, 'utf-8');\n await fs.rename(tmpPath, filePath);\n}\n","/**\n * Persistence Layer\n *\n * Saves and restores the Orama database to/from disk.\n * Source: @orama/plugin-data-persistence (official Orama plugin)\n *\n * Data is stored in a single FLAT global directory shared across ALL agents and projects:\n * ~/.memorix/data/ (observations.json, graph.jsonl, counter.json, sessions.json)\n *\n * projectId is metadata only — stored inside each observation record,\n * NOT used for directory partitioning. This ensures cross-IDE relay works\n * even when different IDEs detect different projectIds for the same repo.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { atomicWriteFile } from './file-lock.js';\n\n/** Default base data directory — overridable via MEMORIX_DATA_DIR env var */\nconst DEFAULT_DATA_DIR = process.env.MEMORIX_DATA_DIR || path.join(os.homedir(), '.memorix', 'data');\n\n/**\n * Sanitize a projectId for use as a directory name.\n * Used only during migration to locate legacy per-project subdirectories.\n */\nfunction sanitizeProjectId(projectId: string): string {\n return projectId.replace(/\\//g, '--').replace(/[<>:\"|?*\\\\]/g, '_');\n}\n\n/**\n * Get the data directory for Memorix storage.\n *\n * Returns the FLAT global directory (~/.memorix/data/) regardless of projectId.\n * projectId is stored as metadata inside observations, not used for directory partitioning.\n * This ensures all IDEs share the same data directory even if they detect different projectIds.\n *\n * @param _projectId - Ignored for directory purposes (kept for API compat)\n */\nexport async function getProjectDataDir(_projectId: string, baseDir?: string): Promise<string> {\n // Legacy guard — detectProject no longer returns __invalid__ (uses placeholder/ instead)\n // Keep check for safety but should never trigger in normal operation\n const base = baseDir ?? DEFAULT_DATA_DIR;\n await fs.mkdir(base, { recursive: true });\n return base;\n}\n\n/**\n * Get the base data directory (parent of all project dirs).\n */\nexport function getBaseDataDir(baseDir?: string): string {\n return baseDir ?? DEFAULT_DATA_DIR;\n}\n\n/**\n * List all project data directories.\n * Used for cross-project (global) search.\n */\nexport async function listProjectDirs(baseDir?: string): Promise<string[]> {\n const base = baseDir ?? DEFAULT_DATA_DIR;\n try {\n const entries = await fs.readdir(base, { withFileTypes: true });\n return entries\n .filter((e) => e.isDirectory())\n .map((e) => path.join(base, e.name));\n } catch {\n return [];\n }\n}\n\n/**\n * Migrate legacy per-project subdirectories into the flat base directory.\n *\n * Before v0.9.6, data was stored in per-project subdirectories:\n * ~/.memorix/data/AVIDS2--memorix/observations.json\n * ~/.memorix/data/local--myproject/observations.json\n *\n * This caused data fragmentation when different IDEs detected different projectIds.\n * Now all data lives in ~/.memorix/data/ directly.\n *\n * Migration:\n * 1. Scan all subdirectories under base dir\n * 2. Merge observations from all subdirs into base dir (remap IDs to avoid collision)\n * 3. Merge graph.jsonl (deduplicate entities by name)\n * 4. Move subdirectories to .migrated-subdirs/ backup\n */\nexport async function migrateSubdirsToFlat(baseDir?: string): Promise<boolean> {\n const base = baseDir ?? DEFAULT_DATA_DIR;\n await fs.mkdir(base, { recursive: true });\n\n // Find all subdirectories that contain observations.json\n let entries: import('node:fs').Dirent[];\n try {\n entries = await fs.readdir(base, { withFileTypes: true });\n } catch {\n return false;\n }\n\n const dataDirs = entries\n .filter((e) => e.isDirectory() && !e.name.startsWith('.'))\n .map((e) => path.join(base, e.name));\n\n if (dataDirs.length === 0) return false;\n\n // Check which subdirs actually have observation data\n const subdirData: Array<{ dir: string; obs: any[]; graph: { entities: any[]; relations: any[] } }> = [];\n for (const dir of dataDirs) {\n const obsPath = path.join(dir, 'observations.json');\n try {\n const data = await fs.readFile(obsPath, 'utf-8');\n const obs = JSON.parse(data);\n if (Array.isArray(obs) && obs.length > 0) {\n // Also try to load graph\n let graph = { entities: [] as any[], relations: [] as any[] };\n try {\n const graphData = await fs.readFile(path.join(dir, 'graph.jsonl'), 'utf-8');\n const lines = graphData.split('\\n').filter((l: string) => l.trim());\n for (const line of lines) {\n const item = JSON.parse(line);\n if (item.type === 'entity') graph.entities.push(item);\n if (item.type === 'relation') graph.relations.push(item);\n }\n } catch { /* no graph */ }\n subdirData.push({ dir, obs, graph });\n }\n } catch { /* no observations */ }\n }\n\n if (subdirData.length === 0) return false;\n\n // Load existing base-level data (if any)\n let baseObs: any[] = [];\n try {\n const data = await fs.readFile(path.join(base, 'observations.json'), 'utf-8');\n baseObs = JSON.parse(data);\n if (!Array.isArray(baseObs)) baseObs = [];\n } catch { /* no existing base data */ }\n\n let baseGraph = { entities: [] as any[], relations: [] as any[] };\n try {\n const graphData = await fs.readFile(path.join(base, 'graph.jsonl'), 'utf-8');\n const lines = graphData.split('\\n').filter((l: string) => l.trim());\n for (const line of lines) {\n const item = JSON.parse(line);\n if (item.type === 'entity') baseGraph.entities.push(item);\n if (item.type === 'relation') baseGraph.relations.push(item);\n }\n } catch { /* no graph */ }\n\n // Merge all observations: collect, sort by createdAt, remap IDs\n const allObs: any[] = [...baseObs];\n for (const { obs } of subdirData) {\n for (const o of obs) {\n // Deduplicate by title+createdAt+projectId (same observation from migration overlap)\n const isDuplicate = allObs.some(\n (existing) => existing.title === o.title && existing.createdAt === o.createdAt,\n );\n if (!isDuplicate) {\n allObs.push(o);\n }\n }\n }\n\n // Sort by createdAt then remap IDs sequentially\n allObs.sort((a, b) => (a.createdAt || '').localeCompare(b.createdAt || ''));\n for (let i = 0; i < allObs.length; i++) {\n allObs[i].id = i + 1;\n }\n\n // Merge graphs (deduplicate entities by name)\n const entityMap = new Map<string, any>();\n for (const e of baseGraph.entities) entityMap.set(e.name, e);\n for (const { graph } of subdirData) {\n for (const e of graph.entities) {\n if (!entityMap.has(e.name)) {\n entityMap.set(e.name, e);\n } else {\n // Merge observations lists\n const existing = entityMap.get(e.name);\n const obsSet = new Set([...(existing.observations || []), ...(e.observations || [])]);\n existing.observations = [...obsSet];\n }\n }\n }\n\n const relationSet = new Set<string>();\n const mergedRelations: any[] = [];\n for (const rel of [...baseGraph.relations, ...subdirData.flatMap((d) => d.graph.relations)]) {\n const key = `${rel.from}|${rel.to}|${rel.relationType}`;\n if (!relationSet.has(key)) {\n relationSet.add(key);\n mergedRelations.push(rel);\n }\n }\n\n // Write merged data to base directory\n await fs.writeFile(path.join(base, 'observations.json'), JSON.stringify(allObs, null, 2), 'utf-8');\n await fs.writeFile(\n path.join(base, 'counter.json'),\n JSON.stringify({ nextId: allObs.length + 1 }),\n 'utf-8',\n );\n\n // Write merged graph\n const graphLines = [\n ...[...entityMap.values()].map((e) => JSON.stringify({ type: 'entity', name: e.name, entityType: e.entityType, observations: e.observations })),\n ...mergedRelations.map((r) => JSON.stringify({ type: 'relation', from: r.from, to: r.to, relationType: r.relationType })),\n ];\n if (graphLines.length > 0) {\n await fs.writeFile(path.join(base, 'graph.jsonl'), graphLines.join('\\n'), 'utf-8');\n }\n\n // Also merge sessions if present\n let allSessions: any[] = [];\n try {\n const data = await fs.readFile(path.join(base, 'sessions.json'), 'utf-8');\n allSessions = JSON.parse(data);\n if (!Array.isArray(allSessions)) allSessions = [];\n } catch { /* no sessions */ }\n for (const { dir } of subdirData) {\n try {\n const data = await fs.readFile(path.join(dir, 'sessions.json'), 'utf-8');\n const sessions = JSON.parse(data);\n if (Array.isArray(sessions)) allSessions.push(...sessions);\n } catch { /* no sessions */ }\n }\n if (allSessions.length > 0) {\n await fs.writeFile(path.join(base, 'sessions.json'), JSON.stringify(allSessions, null, 2), 'utf-8');\n }\n\n // Move subdirectories to backup\n const backupDir = path.join(base, '.migrated-subdirs');\n await fs.mkdir(backupDir, { recursive: true });\n for (const { dir } of subdirData) {\n const dirName = path.basename(dir);\n try {\n await fs.rename(dir, path.join(backupDir, dirName));\n } catch {\n // If rename fails (cross-device), try to just leave it\n // The important thing is the merged data is written\n }\n }\n\n // Also move remaining empty subdirectories\n for (const dir of dataDirs) {\n const dirName = path.basename(dir);\n try {\n await fs.access(dir);\n await fs.rename(dir, path.join(backupDir, dirName));\n } catch { /* already moved or doesn't exist */ }\n }\n\n return true;\n}\n\n/**\n * Get the file path for the Orama database file.\n */\nexport function getDbFilePath(projectDir: string): string {\n return path.join(projectDir, 'memorix.msp');\n}\n\n/**\n * Get the file path for the knowledge graph JSONL file.\n * (MCP-compatible format, same as official Memory Server)\n */\nexport function getGraphFilePath(projectDir: string): string {\n return path.join(projectDir, 'graph.jsonl');\n}\n\n/**\n * Check if a database file exists for the given project.\n */\nexport async function hasExistingData(projectDir: string): Promise<boolean> {\n try {\n await fs.access(getDbFilePath(projectDir));\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Save the knowledge graph in JSONL format (MCP-compatible).\n * Each line is a JSON object with type: \"entity\" or \"relation\".\n *\n * Format adopted from MCP Official Memory Server.\n */\nexport async function saveGraphJsonl(\n projectDir: string,\n entities: Array<{ name: string; entityType: string; observations: string[] }>,\n relations: Array<{ from: string; to: string; relationType: string }>,\n): Promise<void> {\n const lines = [\n ...entities.map((e) =>\n JSON.stringify({ type: 'entity', name: e.name, entityType: e.entityType, observations: e.observations }),\n ),\n ...relations.map((r) =>\n JSON.stringify({ type: 'relation', from: r.from, to: r.to, relationType: r.relationType }),\n ),\n ];\n await atomicWriteFile(getGraphFilePath(projectDir), lines.join('\\n'));\n}\n\n/**\n * Load the knowledge graph from JSONL format.\n */\nexport async function loadGraphJsonl(\n projectDir: string,\n): Promise<{\n entities: Array<{ name: string; entityType: string; observations: string[] }>;\n relations: Array<{ from: string; to: string; relationType: string }>;\n}> {\n const filePath = getGraphFilePath(projectDir);\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n const lines = data.split('\\n').filter((line) => line.trim() !== '');\n return lines.reduce(\n (graph, line) => {\n const item = JSON.parse(line);\n if (item.type === 'entity') {\n graph.entities.push({\n name: item.name,\n entityType: item.entityType,\n observations: item.observations,\n });\n }\n if (item.type === 'relation') {\n graph.relations.push({\n from: item.from,\n to: item.to,\n relationType: item.relationType,\n });\n }\n return graph;\n },\n {\n entities: [] as Array<{ name: string; entityType: string; observations: string[] }>,\n relations: [] as Array<{ from: string; to: string; relationType: string }>\n },\n );\n } catch (error) {\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n return { entities: [], relations: [] };\n }\n throw error;\n }\n}\n\n/**\n * Save observation data as JSON (for Orama restore).\n */\nexport async function saveObservationsJson(\n projectDir: string,\n observations: unknown[],\n): Promise<void> {\n const filePath = path.join(projectDir, 'observations.json');\n await atomicWriteFile(filePath, JSON.stringify(observations, null, 2));\n}\n\n/**\n * Load observation data from JSON.\n */\nexport async function loadObservationsJson(projectDir: string): Promise<unknown[]> {\n const filePath = path.join(projectDir, 'observations.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(data);\n } catch (error) {\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Save the next observation ID counter.\n */\nexport async function saveIdCounter(projectDir: string, nextId: number): Promise<void> {\n const filePath = path.join(projectDir, 'counter.json');\n await atomicWriteFile(filePath, JSON.stringify({ nextId }));\n}\n\n/**\n * Append archived observations to the archive file.\n * Archived observations are moved here by the retention engine.\n */\nexport async function appendArchivedObservations(\n projectDir: string,\n observations: unknown[],\n): Promise<void> {\n const filePath = path.join(projectDir, 'observations.archived.json');\n let existing: unknown[] = [];\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n existing = JSON.parse(data);\n if (!Array.isArray(existing)) existing = [];\n } catch { /* no archive yet */ }\n existing.push(...observations);\n await atomicWriteFile(filePath, JSON.stringify(existing, null, 2));\n}\n\n/**\n * Load archived observations.\n */\nexport async function loadArchivedObservations(projectDir: string): Promise<unknown[]> {\n const filePath = path.join(projectDir, 'observations.archived.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch {\n return [];\n }\n}\n\n/**\n * Load the next observation ID counter.\n */\nexport async function loadIdCounter(projectDir: string): Promise<number> {\n const filePath = path.join(projectDir, 'counter.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(data).nextId ?? 1;\n } catch {\n return 1;\n }\n}\n\n/**\n * Save mini-skills data as JSON.\n */\nexport async function saveMiniSkillsJson(\n projectDir: string,\n skills: unknown[],\n): Promise<void> {\n const filePath = path.join(projectDir, 'mini-skills.json');\n await atomicWriteFile(filePath, JSON.stringify(skills, null, 2));\n}\n\n/**\n * Load mini-skills data from JSON.\n */\nexport async function loadMiniSkillsJson(projectDir: string): Promise<unknown[]> {\n const filePath = path.join(projectDir, 'mini-skills.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n const parsed = JSON.parse(data);\n return Array.isArray(parsed) ? parsed : [];\n } catch (error) {\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n return [];\n }\n throw error;\n }\n}\n\n/**\n * Load the mini-skills ID counter.\n */\nexport async function loadMiniSkillsCounter(projectDir: string): Promise<number> {\n const filePath = path.join(projectDir, 'mini-skills-counter.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(data).nextId ?? 1;\n } catch {\n return 1;\n }\n}\n\n/**\n * Save the mini-skills ID counter.\n */\nexport async function saveMiniSkillsCounter(projectDir: string, nextId: number): Promise<void> {\n const filePath = path.join(projectDir, 'mini-skills-counter.json');\n await atomicWriteFile(filePath, JSON.stringify({ nextId }));\n}\n\n/**\n * Save sessions data as JSON.\n */\nexport async function saveSessionsJson(\n projectDir: string,\n sessions: unknown[],\n): Promise<void> {\n const filePath = path.join(projectDir, 'sessions.json');\n await atomicWriteFile(filePath, JSON.stringify(sessions, null, 2));\n}\n\n/**\n * Load sessions data from JSON.\n */\nexport async function loadSessionsJson(projectDir: string): Promise<unknown[]> {\n const filePath = path.join(projectDir, 'sessions.json');\n try {\n const data = await fs.readFile(filePath, 'utf-8');\n return JSON.parse(data);\n } catch (error) {\n if (error instanceof Error && 'code' in error && (error as NodeJS.ErrnoException).code === 'ENOENT') {\n return [];\n }\n throw error;\n }\n}\n","/**\n * Memorix Core Types\n *\n * Data model sources:\n * - Entity/Relation/KnowledgeGraph: MCP Official Memory Server (v0.6.3)\n * - Observation/ObservationType: claude-mem Progressive Disclosure\n * - UnifiedRule/RuleSource: Memorix original (rules sync)\n *\n * Designed for extensibility: new agent formats (Kiro, Copilot, Antigravity)\n * can be added by extending RuleSource and adding format adapters.\n */\n\n// ============================================================\n// Knowledge Graph (adopted from MCP Official Memory Server)\n// ============================================================\n\n/** A node in the knowledge graph representing a concept, component, or config */\nexport interface Entity {\n name: string;\n entityType: string;\n observations: string[];\n}\n\n/** A directed edge between two entities */\nexport interface Relation {\n from: string;\n to: string;\n relationType: string;\n}\n\n/** The complete knowledge graph */\nexport interface KnowledgeGraph {\n entities: Entity[];\n relations: Relation[];\n}\n\n// ============================================================\n// Observation (adopted from claude-mem Progressive Disclosure)\n// ============================================================\n\n/**\n * Observation type classification using claude-mem's icon-based legend system.\n *\n * Icon mapping:\n * 🎯 session-request — User's original goal\n * 🔴 gotcha — Critical pitfall / trap\n * 🟡 problem-solution — Bug fix or workaround\n * 🔵 how-it-works — Technical explanation\n * 🟢 what-changed — Code/architecture change\n * 🟣 discovery — New learning or insight\n * 🟠 why-it-exists — Design rationale\n * 🟤 decision — Architecture decision\n * ⚖️ trade-off — Deliberate compromise\n */\nexport type ObservationType =\n | 'session-request'\n | 'gotcha'\n | 'problem-solution'\n | 'how-it-works'\n | 'what-changed'\n | 'discovery'\n | 'why-it-exists'\n | 'decision'\n | 'trade-off';\n\n/** Map from ObservationType to display icon */\nexport const OBSERVATION_ICONS: Record<ObservationType, string> = {\n 'session-request': '🎯',\n 'gotcha': '🔴',\n 'problem-solution': '🟡',\n 'how-it-works': '🔵',\n 'what-changed': '🟢',\n 'discovery': '🟣',\n 'why-it-exists': '🟠',\n 'decision': '🟤',\n 'trade-off': '⚖️',\n};\n\n/** Observation lifecycle status */\nexport type ObservationStatus = 'active' | 'resolved' | 'archived';\n\n/** Progress tracking for task/feature observations */\nexport interface ProgressInfo {\n feature: string;\n status: 'in-progress' | 'completed' | 'blocked';\n completion?: number;\n}\n\n/** A rich observation record attached to an entity */\nexport interface Observation {\n id: number;\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts: string[];\n filesModified: string[];\n concepts: string[];\n tokens: number;\n createdAt: string;\n updatedAt?: string;\n projectId: string;\n /** Whether the observation contains causal language (because, due to, etc.) */\n hasCausalLanguage?: boolean;\n /** Optional topic key for upsert — same project+topicKey updates existing observation */\n topicKey?: string;\n /** How many times this observation was revised via topic key upsert (starts at 1) */\n revisionCount?: number;\n /** Session ID this observation belongs to */\n sessionId?: string;\n /** Lifecycle status: active (default) → resolved → archived */\n status?: ObservationStatus;\n /** ID of the observation that superseded this one (set when auto-resolved by topicKey upsert) */\n supersededBy?: number;\n /** Progress tracking for task/feature observations */\n progress?: ProgressInfo;\n}\n\n// ============================================================\n// Session Lifecycle (inspired by Engram's session management)\n// ============================================================\n\n/** A coding session tracked by Memorix */\nexport interface Session {\n id: string;\n projectId: string;\n startedAt: string;\n endedAt?: string;\n summary?: string;\n status: 'active' | 'completed';\n /** Agent/IDE that started this session */\n agent?: string;\n}\n\n// ============================================================\n// Compact Engine (adopted from claude-mem 3-layer workflow)\n// ============================================================\n\n/** L1 index entry — lightweight, ~50-100 tokens per result */\nexport interface IndexEntry {\n id: number;\n time: string;\n type: ObservationType;\n icon: string;\n title: string;\n tokens: number;\n /** Relevance score from search (time-decayed). Used by compact engine. */\n score?: number;\n}\n\n/** L2 timeline context — observations around an anchor */\nexport interface TimelineContext {\n anchorId: number;\n anchorEntry: IndexEntry | null;\n before: IndexEntry[];\n after: IndexEntry[];\n}\n\n/** Search options for the compact engine */\nexport interface SearchOptions {\n query: string;\n limit?: number;\n type?: ObservationType;\n projectId?: string;\n since?: string;\n until?: string;\n /** Token budget — trim results to fit within this many tokens (0 = unlimited) */\n maxTokens?: number;\n /** Filter by observation status. Default: 'active' (only show active memories) */\n status?: ObservationStatus | 'all';\n}\n\n/** Topic key family heuristics for suggesting stable topic keys */\nexport const TOPIC_KEY_FAMILIES: Record<string, string[]> = {\n 'architecture': ['architecture', 'design', 'adr', 'structure', 'pattern'],\n 'bug': ['bugfix', 'fix', 'error', 'regression', 'crash', 'problem-solution'],\n 'decision': ['decision', 'trade-off', 'choice', 'strategy'],\n 'config': ['config', 'setup', 'env', 'environment', 'deployment'],\n 'discovery': ['discovery', 'learning', 'insight', 'gotcha'],\n 'pattern': ['pattern', 'convention', 'standard', 'best-practice'],\n};\n\n// ============================================================\n// Orama Document Schema\n// ============================================================\n\n/** The document shape stored in Orama */\nexport interface MemorixDocument {\n id: string;\n observationId: number;\n entityName: string;\n type: string;\n title: string;\n narrative: string;\n facts: string;\n filesModified: string;\n concepts: string;\n tokens: number;\n createdAt: string;\n projectId: string;\n /** Number of times this observation was returned in search results */\n accessCount: number;\n /** ISO timestamp of last access via search/detail */\n lastAccessedAt: string;\n /** Lifecycle status: active, resolved, archived */\n status: string;\n}\n\n// ============================================================\n// Rules System (Memorix original — extensible for new agents)\n// ============================================================\n\n/**\n * Supported agent/IDE rule sources.\n * All 7 major AI IDEs are supported.\n */\nexport type RuleSource =\n | 'cursor'\n | 'claude-code'\n | 'codex'\n | 'windsurf'\n | 'antigravity'\n | 'copilot'\n | 'kiro'\n | 'trae'\n | 'memorix';\n\n/** A parsed rule in the unified intermediate representation */\nexport interface UnifiedRule {\n id: string;\n content: string;\n description?: string;\n source: RuleSource;\n scope: 'global' | 'project' | 'path-specific';\n paths?: string[];\n alwaysApply?: boolean;\n priority: number;\n hash: string;\n}\n\n/**\n * Format adapter interface — implement this for each agent/IDE.\n * Adding a new agent (e.g., Kiro) only requires implementing this interface.\n */\nexport interface RuleFormatAdapter {\n /** Unique identifier for this agent format */\n readonly source: RuleSource;\n\n /** File paths/globs this adapter can parse */\n readonly filePatterns: string[];\n\n /** Parse rule files into unified representation */\n parse(filePath: string, content: string): UnifiedRule[];\n\n /** Generate rule file content from unified representation */\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[];\n}\n\n// ============================================================\n// Project Identity\n// ============================================================\n\nexport interface ProjectInfo {\n id: string;\n name: string;\n gitRemote?: string;\n rootPath: string;\n}\n\n// ============================================================\n// Memorix Server Configuration\n// ============================================================\n\nexport interface MemorixConfig {\n dataDir: string;\n projectId: string;\n projectName: string;\n enableEmbeddings: boolean;\n enableRulesSync: boolean;\n watchRuleFiles: boolean;\n}\n\nexport const DEFAULT_CONFIG: Partial<MemorixConfig> = {\n enableEmbeddings: false,\n enableRulesSync: false,\n watchRuleFiles: false,\n};\n\n// ============================================================\n// Workspace Sync — Cross-Agent workspace migration\n// ============================================================\n\n/** Supported agent targets for workspace sync */\nexport type AgentTarget = 'windsurf' | 'cursor' | 'claude-code' | 'codex' | 'copilot' | 'antigravity' | 'kiro' | 'opencode' | 'trae';\n\n/** A unified MCP server entry across all agent config formats */\nexport interface MCPServerEntry {\n name: string;\n /** Command for stdio transport */\n command: string;\n /** Args for stdio transport */\n args: string[];\n /** Environment variables */\n env?: Record<string, string> | null;\n /** URL for HTTP/SSE transport (Codex uses `url`, Windsurf uses `serverUrl`) */\n url?: string;\n /** HTTP headers (Windsurf uses `headers` for HTTP transport) */\n headers?: Record<string, string>;\n /** Whether this server is disabled */\n disabled?: boolean;\n}\n\n/** Unified workflow entry */\nexport interface WorkflowEntry {\n name: string;\n description: string;\n content: string;\n source: AgentTarget;\n filePath: string;\n}\n\n/** A skill folder discovered from an agent's skills directory */\nexport interface SkillEntry {\n name: string;\n description: string;\n sourcePath: string;\n sourceAgent: AgentTarget;\n}\n\n/** Conflict when two agents have a skill with the same folder name */\nexport interface SkillConflict {\n name: string;\n kept: SkillEntry;\n skipped: SkillEntry;\n}\n\n/** Result of a workspace sync operation */\nexport interface WorkspaceSyncResult {\n mcpServers: {\n scanned: MCPServerEntry[];\n generated: { filePath: string; content: string }[];\n };\n workflows: {\n scanned: WorkflowEntry[];\n generated: { filePath: string; content: string }[];\n };\n rules: {\n scanned: number;\n generated: number;\n };\n skills: {\n scanned: SkillEntry[];\n conflicts: SkillConflict[];\n copied: string[];\n skipped: string[];\n };\n}\n\n// ============================================================\n// Mini-Skills — Promoted memories that never decay\n// ============================================================\n\n/** A mini-skill promoted from one or more observations */\nexport interface MiniSkill {\n id: number;\n /** Observation IDs this mini-skill was derived from */\n sourceObservationIds: number[];\n /** Entity the source observations belong to */\n sourceEntity: string;\n /** Short title for the skill */\n title: string;\n /** What the agent should do (imperative instruction) */\n instruction: string;\n /** When this skill should be applied (scenario description) */\n trigger: string;\n /** Key facts extracted from source observations */\n facts: string[];\n /** Project this skill belongs to */\n projectId: string;\n /** ISO timestamp */\n createdAt: string;\n /** How many times this skill was injected in session_start */\n usedCount: number;\n /** Classification tags */\n tags: string[];\n}\n\n/** MCP config format adapter interface */\nexport interface MCPConfigAdapter {\n readonly source: AgentTarget;\n /** Parse MCP server entries from a config file */\n parse(content: string): MCPServerEntry[];\n /** Generate config file content from MCP server entries */\n generate(servers: MCPServerEntry[]): string;\n /** Get the default config file path for this agent */\n getConfigPath(projectRoot?: string): string;\n}\n","/**\n * Unified Configuration Reader\n *\n * Priority chain (highest wins):\n * 1. Environment variables (from MCP JSON `env` field or system env)\n * 2. ~/.memorix/config.json (written by `memorix configure` TUI)\n * 3. Hardcoded defaults\n *\n * This ensures `memorix configure` actually takes effect at runtime,\n * while env vars can still override for advanced users.\n */\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface MemorixConfig {\n llm?: {\n provider?: string;\n apiKey?: string;\n model?: string;\n baseUrl?: string;\n };\n embedding?: string;\n embeddingApi?: {\n apiKey?: string;\n baseUrl?: string;\n model?: string;\n dimensions?: number;\n };\n}\n\n// ─── Singleton ───────────────────────────────────────────────────────\n\nlet cachedConfig: MemorixConfig | null = null;\n\n/**\n * Load config from ~/.memorix/config.json.\n * Cached after first load. Returns empty object on failure.\n */\nexport function loadFileConfig(): MemorixConfig {\n if (cachedConfig !== null) return cachedConfig;\n\n const configPath = join(homedir(), '.memorix', 'config.json');\n try {\n if (existsSync(configPath)) {\n cachedConfig = JSON.parse(readFileSync(configPath, 'utf-8'));\n return cachedConfig!;\n }\n } catch {\n // Corrupt or unreadable — ignore\n }\n cachedConfig = {};\n return cachedConfig;\n}\n\n/**\n * Reset cached config (for testing).\n */\nexport function resetConfigCache(): void {\n cachedConfig = null;\n}\n\n// ─── Resolved Getters (env > config.json > default) ──────────────────\n\n/** LLM API key: MEMORIX-specific env > config.json > generic env fallback */\nexport function getLLMApiKey(): string | undefined {\n return (\n process.env.MEMORIX_LLM_API_KEY ||\n loadFileConfig().llm?.apiKey ||\n process.env.OPENAI_API_KEY ||\n process.env.ANTHROPIC_API_KEY ||\n process.env.OPENROUTER_API_KEY ||\n undefined\n );\n}\n\n/** LLM provider: env > config.json > auto-detect */\nexport function getLLMProvider(): string {\n if (process.env.MEMORIX_LLM_PROVIDER) return process.env.MEMORIX_LLM_PROVIDER;\n const cfg = loadFileConfig();\n if (cfg.llm?.provider) return cfg.llm.provider;\n // Auto-detect from env var names\n if (process.env.ANTHROPIC_API_KEY && !process.env.OPENAI_API_KEY) return 'anthropic';\n if (process.env.OPENROUTER_API_KEY && !process.env.OPENAI_API_KEY) return 'openrouter';\n return 'openai';\n}\n\n/** LLM model: env > config.json > provider default */\nexport function getLLMModel(providerDefault: string): string {\n return process.env.MEMORIX_LLM_MODEL || loadFileConfig().llm?.model || providerDefault;\n}\n\n/** LLM base URL: env > config.json > provider default */\nexport function getLLMBaseUrl(providerDefault: string): string {\n return process.env.MEMORIX_LLM_BASE_URL || loadFileConfig().llm?.baseUrl || providerDefault;\n}\n\n/** Embedding mode: env > config.json > 'off' */\nexport function getEmbeddingMode(): 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' {\n const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();\n if (env === 'fastembed' || env === 'transformers' || env === 'api' || env === 'auto') return env;\n const cfg = loadFileConfig();\n if (cfg.embedding === 'fastembed' || cfg.embedding === 'transformers' || cfg.embedding === 'api' || cfg.embedding === 'auto') {\n return cfg.embedding;\n }\n return 'off';\n}\n\n/** Embedding API key: env > config.json > LLM key fallback */\nexport function getEmbeddingApiKey(): string | undefined {\n return (\n process.env.MEMORIX_EMBEDDING_API_KEY ||\n loadFileConfig().embeddingApi?.apiKey ||\n process.env.MEMORIX_LLM_API_KEY ||\n loadFileConfig().llm?.apiKey ||\n process.env.OPENAI_API_KEY ||\n undefined\n );\n}\n\n/** Embedding base URL: env > config.json > LLM URL fallback */\nexport function getEmbeddingBaseUrl(): string {\n return (\n process.env.MEMORIX_EMBEDDING_BASE_URL ||\n loadFileConfig().embeddingApi?.baseUrl ||\n process.env.MEMORIX_LLM_BASE_URL ||\n loadFileConfig().llm?.baseUrl ||\n 'https://api.openai.com/v1'\n );\n}\n\n/** Embedding model: env > config.json > default */\nexport function getEmbeddingModel(): string {\n return (\n process.env.MEMORIX_EMBEDDING_MODEL ||\n loadFileConfig().embeddingApi?.model ||\n 'text-embedding-3-small'\n );\n}\n\n/** Embedding dimensions override: env > config.json > null (auto-detect) */\nexport function getEmbeddingDimensions(): number | null {\n const envDim = process.env.MEMORIX_EMBEDDING_DIMENSIONS;\n if (envDim) return parseInt(envDim, 10);\n const cfgDim = loadFileConfig().embeddingApi?.dimensions;\n if (cfgDim) return cfgDim;\n return null;\n}\n","/**\n * FastEmbed Provider\n *\n * Local ONNX-based embedding using fastembed (Qdrant).\n * Model: BAAI/bge-small-en-v1.5 (384 dimensions, ~30MB)\n *\n * This is an optional dependency — if fastembed is not installed,\n * the provider module gracefully falls back to fulltext-only search.\n *\n * Persistent disk cache: embeddings are saved to ~/.memorix/data/.embedding-cache.json\n * so server restarts don't need to regenerate them (saves minutes of CPU on 500+ obs).\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { EmbeddingProvider } from './provider.js';\n\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-cache.json');\n\n// In-memory cache keyed by text hash → embedding\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 5000;\nlet diskCacheDirty = false;\n\nfunction textHash(text: string): string {\n return createHash('sha256').update(text).digest('hex').slice(0, 16);\n}\n\nasync function loadDiskCache(): Promise<void> {\n try {\n const raw = await readFile(CACHE_FILE, 'utf-8');\n const entries: [string, number[]][] = JSON.parse(raw);\n for (const [k, v] of entries) cache.set(k, v);\n console.error(`[memorix] Loaded ${entries.length} cached embeddings from disk`);\n } catch {\n // No cache file or corrupt — start fresh\n }\n}\n\nasync function saveDiskCache(): Promise<void> {\n if (!diskCacheDirty) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const entries = Array.from(cache.entries());\n await writeFile(CACHE_FILE, JSON.stringify(entries));\n diskCacheDirty = false;\n } catch {\n // Ignore write errors — cache is an optimization, not critical\n }\n}\n\nexport class FastEmbedProvider implements EmbeddingProvider {\n readonly name = 'fastembed-bge-small';\n readonly dimensions = 384;\n\n private model: { embed: (docs: string[], batchSize?: number) => AsyncGenerator<number[][]>; queryEmbed: (query: string) => Promise<number[]> };\n\n private constructor(model: FastEmbedProvider['model']) {\n this.model = model;\n }\n\n /**\n * Initialize the FastEmbed provider.\n * Downloads model on first use (~30MB), cached locally after.\n * Loads persistent embedding cache from disk.\n */\n static async create(): Promise<FastEmbedProvider> {\n // Dynamic import — throws if fastembed is not installed\n const { EmbeddingModel, FlagEmbedding } = await import('fastembed');\n const model = await FlagEmbedding.init({\n model: EmbeddingModel.BGESmallENV15,\n });\n // Load disk cache before returning — subsequent embedBatch calls will hit cache\n await loadDiskCache();\n return new FastEmbedProvider(model);\n }\n\n async embed(text: string): Promise<number[]> {\n const hash = textHash(text);\n const cached = cache.get(hash);\n if (cached) return cached;\n\n const raw = await this.model.queryEmbed(text);\n // Ensure plain number[] (fastembed may return Float32Array)\n const result = Array.from(raw) as number[];\n if (result.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);\n }\n this.cacheSet(hash, result);\n return result;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n // Check cache for each text (by hash)\n for (let i = 0; i < texts.length; i++) {\n const hash = textHash(texts[i]);\n const cached = cache.get(hash);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(texts[i]);\n }\n }\n\n // Batch embed uncached texts\n if (uncachedTexts.length > 0) {\n console.error(`[memorix] Embedding ${uncachedTexts.length}/${texts.length} uncached texts (${texts.length - uncachedTexts.length} from cache)`);\n let batchIdx = 0;\n for await (const batch of this.model.embed(uncachedTexts, 64)) {\n for (const vec of batch) {\n const originalIdx = uncachedIndices[batchIdx];\n const plain = Array.from(vec) as number[];\n results[originalIdx] = plain;\n this.cacheSet(textHash(uncachedTexts[batchIdx]), plain);\n batchIdx++;\n }\n }\n // Persist cache to disk after batch operations\n await saveDiskCache();\n }\n\n return results;\n }\n\n private cacheSet(hash: string, value: number[]): void {\n // Evict oldest entries if cache is full\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(hash, value);\n diskCacheDirty = true;\n }\n}\n","/**\r\n * Transformers.js Provider\r\n *\r\n * Pure JavaScript embedding using @huggingface/transformers (HuggingFace).\r\n * Model: Xenova/all-MiniLM-L6-v2 (384 dimensions, ~22MB quantized)\r\n *\r\n * Key advantages over fastembed:\r\n * - No native ONNX binding required (pure JS / WASM)\r\n * - Works out-of-the-box on Windows, macOS, Linux\r\n * - Supports quantized models (q8, q4) for smaller footprint\r\n *\r\n * This is an optional dependency — if @huggingface/transformers is not\r\n * installed, the provider module gracefully falls back to the next option.\r\n *\r\n * Inspired by Mem0's multi-provider embedding architecture.\r\n */\r\n\r\nimport type { EmbeddingProvider } from './provider.js';\r\n\r\n// In-memory LRU cache\r\nconst cache = new Map<string, number[]>();\r\nconst MAX_CACHE_SIZE = 5000;\r\n\r\nexport class TransformersProvider implements EmbeddingProvider {\r\n readonly name = 'transformers-minilm';\r\n readonly dimensions = 384;\r\n\r\n private extractor: any; // Pipeline instance\r\n\r\n private constructor(extractor: any) {\r\n this.extractor = extractor;\r\n }\r\n\r\n /**\r\n * Initialize the Transformers.js provider.\r\n * Downloads model on first use (~22MB quantized), cached locally after.\r\n */\r\n static async create(): Promise<TransformersProvider> {\r\n // Dynamic import — throws if @huggingface/transformers is not installed\r\n const { pipeline } = await import('@huggingface/transformers');\r\n const extractor = await pipeline(\r\n 'feature-extraction',\r\n 'Xenova/all-MiniLM-L6-v2',\r\n { dtype: 'q8' }, // Quantized for small footprint\r\n );\r\n return new TransformersProvider(extractor);\r\n }\r\n\r\n async embed(text: string): Promise<number[]> {\r\n // Check cache first\r\n const cached = cache.get(text);\r\n if (cached) return cached;\r\n\r\n const output = await this.extractor(text, {\r\n pooling: 'mean',\r\n normalize: true,\r\n });\r\n\r\n // output.tolist() returns [[...384 floats]]\r\n const result: number[] = Array.from(output.tolist()[0]);\r\n if (result.length !== this.dimensions) {\r\n throw new Error(`Expected ${this.dimensions}d embedding, got ${result.length}d`);\r\n }\r\n\r\n this.cacheSet(text, result);\r\n return result;\r\n }\r\n\r\n async embedBatch(texts: string[]): Promise<number[][]> {\r\n const results: number[][] = new Array(texts.length);\r\n const uncachedIndices: number[] = [];\r\n const uncachedTexts: string[] = [];\r\n\r\n // Check cache for each text\r\n for (let i = 0; i < texts.length; i++) {\r\n const cached = cache.get(texts[i]);\r\n if (cached) {\r\n results[i] = cached;\r\n } else {\r\n uncachedIndices.push(i);\r\n uncachedTexts.push(texts[i]);\r\n }\r\n }\r\n\r\n // Batch embed uncached texts\r\n if (uncachedTexts.length > 0) {\r\n const output = await this.extractor(uncachedTexts, {\r\n pooling: 'mean',\r\n normalize: true,\r\n });\r\n const allVecs: number[][] = output.tolist();\r\n\r\n for (let i = 0; i < allVecs.length; i++) {\r\n const vec = Array.from(allVecs[i]) as number[];\r\n const originalIdx = uncachedIndices[i];\r\n results[originalIdx] = vec;\r\n this.cacheSet(uncachedTexts[i], vec);\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n private cacheSet(key: string, value: number[]): void {\r\n if (cache.size >= MAX_CACHE_SIZE) {\r\n const firstKey = cache.keys().next().value;\r\n if (firstKey !== undefined) cache.delete(firstKey);\r\n }\r\n cache.set(key, value);\r\n }\r\n}\r\n","/**\n * API Embedding Provider\n *\n * Remote embedding via any OpenAI-compatible /v1/embeddings endpoint.\n * Works with: OpenAI, Qwen (DashScope), Cohere, 中转站/反代, Ollama, etc.\n *\n * Advantages over local providers:\n * - Zero local resource usage (no 300-500MB RAM)\n * - Access to larger, higher-quality models (1024-3072 dimensions)\n * - Works on any machine without native bindings\n *\n * Performance advantages vs competitors (mcp-memory-service, claude-mem, Mem0):\n * ┌────────────────────────────┬──────────────┬──────────────────────────┐\n * │ Feature │ Competitors │ Memorix │\n * ├────────────────────────────┼──────────────┼──────────────────────────┤\n * │ Embedding cache │ None │ 10K LRU + disk persist │\n * │ Batch API calls │ 1-by-1 │ Up to 2048 per request │\n * │ Cache hit → API bypass │ No │ SHA-256 dedup, 0ms │\n * │ Retry with backoff │ Crash/skip │ Exponential + Retry-After│\n * │ Text normalization │ No │ Whitespace + truncation │\n * │ Debounced disk writes │ N/A │ 5s coalesce window │\n * │ Concurrent batch chunks │ Sequential │ Parallel (4 concurrent) │\n * │ Dimension shortening │ Hardcoded │ Runtime configurable │\n * │ External dependency │ Chroma/SQLite│ Zero (native fetch) │\n * │ Input token waste │ Full text │ Truncated to 8191 tokens │\n * └────────────────────────────┴──────────────┴──────────────────────────┘\n *\n * Environment variables:\n * MEMORIX_EMBEDDING=api — enable this provider\n * MEMORIX_EMBEDDING_API_KEY — API key (fallback: MEMORIX_LLM_API_KEY → OPENAI_API_KEY)\n * MEMORIX_EMBEDDING_BASE_URL — base URL (fallback: MEMORIX_LLM_BASE_URL → https://api.openai.com/v1)\n * MEMORIX_EMBEDDING_MODEL — model name (default: text-embedding-3-small)\n * MEMORIX_EMBEDDING_DIMENSIONS — optional dimension override (e.g., 512 for cost savings)\n */\n\nimport { createHash } from 'node:crypto';\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\nimport type { EmbeddingProvider } from './provider.js';\n\n// ─── Cache Configuration ─────────────────────────────────────────────\n\nconst CACHE_DIR = process.env.MEMORIX_DATA_DIR || join(homedir(), '.memorix', 'data');\nconst CACHE_FILE = join(CACHE_DIR, '.embedding-api-cache.json');\n\nconst cache = new Map<string, number[]>();\nconst MAX_CACHE_SIZE = 10000;\nlet diskCacheDirty = false;\nlet diskSaveTimer: ReturnType<typeof setTimeout> | null = null;\n\n/** Max input text length (chars) — prevent token waste on huge texts */\nconst MAX_INPUT_CHARS = 32000;\n\n/** Max concurrent batch chunks to process in parallel */\nconst MAX_CONCURRENCY = 4;\n\n/** Debounce window for disk cache writes (ms) */\nconst DISK_SAVE_DEBOUNCE_MS = 5000;\n\n// ─── API Configuration ───────────────────────────────────────────────\n\n/** Max texts per API batch (OpenAI limit: 2048) */\nconst MAX_BATCH_SIZE = 2048;\n\n/** Max retries for transient failures */\nconst MAX_RETRIES = 3;\n\n/** Base delay for exponential backoff (ms) */\nconst BASE_DELAY_MS = 500;\n\n// ─── Cache Helpers ───────────────────────────────────────────────────\n\n/**\n * Normalize text for consistent cache hits.\n * Collapses whitespace and trims — \"hello world\" and \"hello world\" get same embedding.\n */\nfunction normalizeText(text: string): string {\n return text.replace(/\\s+/g, ' ').trim().slice(0, MAX_INPUT_CHARS);\n}\n\nfunction textHash(text: string): string {\n return createHash('sha256').update(text).digest('hex').slice(0, 16);\n}\n\nasync function loadDiskCache(): Promise<void> {\n try {\n const raw = await readFile(CACHE_FILE, 'utf-8');\n const entries: [string, number[]][] = JSON.parse(raw);\n for (const [k, v] of entries) cache.set(k, v);\n console.error(`[memorix] Loaded ${entries.length} cached API embeddings from disk`);\n } catch {\n // No cache file or corrupt — start fresh\n }\n}\n\nasync function saveDiskCacheNow(): Promise<void> {\n if (!diskCacheDirty) return;\n try {\n await mkdir(CACHE_DIR, { recursive: true });\n const entries = Array.from(cache.entries());\n await writeFile(CACHE_FILE, JSON.stringify(entries));\n diskCacheDirty = false;\n } catch {\n // Ignore write errors — cache is optimization, not critical\n }\n}\n\n/**\n * Debounced disk cache save — coalesces rapid writes into one 5s-delayed write.\n * Competitors write on every single embed call; we batch for I/O efficiency.\n */\nfunction scheduleDiskSave(): void {\n if (diskSaveTimer) clearTimeout(diskSaveTimer);\n diskSaveTimer = setTimeout(() => {\n saveDiskCacheNow().catch(() => {});\n diskSaveTimer = null;\n }, DISK_SAVE_DEBOUNCE_MS);\n}\n\nfunction cacheSet(hash: string, value: number[]): void {\n if (cache.size >= MAX_CACHE_SIZE) {\n const firstKey = cache.keys().next().value;\n if (firstKey !== undefined) cache.delete(firstKey);\n }\n cache.set(hash, value);\n diskCacheDirty = true;\n}\n\n// ─── API Types ───────────────────────────────────────────────────────\n\ninterface EmbeddingAPIResponse {\n object: string;\n data: Array<{\n object: string;\n index: number;\n embedding: number[];\n }>;\n model: string;\n usage?: {\n prompt_tokens: number;\n total_tokens: number;\n };\n}\n\ninterface APIEmbeddingConfig {\n apiKey: string;\n baseUrl: string;\n model: string;\n requestedDimensions: number | null;\n}\n\n// ─── Provider Implementation ─────────────────────────────────────────\n\nexport class APIEmbeddingProvider implements EmbeddingProvider {\n readonly name: string;\n readonly dimensions: number;\n\n private config: APIEmbeddingConfig;\n private totalTokensUsed = 0;\n private totalApiCalls = 0;\n\n private constructor(config: APIEmbeddingConfig, detectedDimensions: number) {\n this.config = config;\n this.dimensions = detectedDimensions;\n this.name = `api-${config.model.replace(/\\//g, '-')}`;\n }\n\n /**\n * Initialize the API embedding provider.\n * Probes the API with a test embedding to detect dimensions.\n */\n static async create(): Promise<APIEmbeddingProvider> {\n const config = APIEmbeddingProvider.resolveConfig();\n\n // Load disk cache\n await loadDiskCache();\n\n // Probe API to detect dimensions\n const probeDimensions = await APIEmbeddingProvider.probeAPI(config);\n\n console.error(`[memorix] API embedding: ${config.model} @ ${config.baseUrl} (${probeDimensions}d)`);\n if (config.requestedDimensions) {\n console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);\n }\n\n return new APIEmbeddingProvider(config, probeDimensions);\n }\n\n /**\n * Resolve configuration from environment variables.\n * Falls back to LLM config → OpenAI defaults.\n */\n private static resolveConfig(): APIEmbeddingConfig {\n // Unified config: env vars > config.json > defaults\n let apiKey: string | undefined;\n let baseUrl: string;\n let model: string;\n let requestedDimensions: number | null;\n\n try {\n const cfg = require('../config.js');\n apiKey = cfg.getEmbeddingApiKey();\n baseUrl = cfg.getEmbeddingBaseUrl();\n model = cfg.getEmbeddingModel();\n requestedDimensions = cfg.getEmbeddingDimensions();\n } catch {\n // Fallback: direct env var reading\n apiKey =\n process.env.MEMORIX_EMBEDDING_API_KEY ||\n process.env.MEMORIX_LLM_API_KEY ||\n process.env.OPENAI_API_KEY;\n baseUrl =\n process.env.MEMORIX_EMBEDDING_BASE_URL ||\n process.env.MEMORIX_LLM_BASE_URL ||\n 'https://api.openai.com/v1';\n model = process.env.MEMORIX_EMBEDDING_MODEL || 'text-embedding-3-small';\n const dimStr = process.env.MEMORIX_EMBEDDING_DIMENSIONS;\n requestedDimensions = dimStr ? parseInt(dimStr, 10) : null;\n }\n\n if (!apiKey) {\n throw new Error(\n 'No API key for embedding. Set MEMORIX_EMBEDDING_API_KEY, MEMORIX_LLM_API_KEY, or OPENAI_API_KEY, or run `memorix configure`.',\n );\n }\n\n baseUrl = baseUrl.replace(/\\/+$/, ''); // Strip trailing slash\n\n return { apiKey, baseUrl, model, requestedDimensions };\n }\n\n /**\n * Probe API with a test text to detect actual output dimensions.\n */\n private static async probeAPI(config: APIEmbeddingConfig): Promise<number> {\n const body: Record<string, unknown> = {\n model: config.model,\n input: 'dimension probe',\n };\n if (config.requestedDimensions) {\n body.dimensions = config.requestedDimensions;\n }\n\n const response = await fetchWithRetry(\n `${config.baseUrl}/embeddings`,\n config.apiKey,\n body,\n );\n\n if (response.data.length === 0 || !response.data[0].embedding) {\n throw new Error('API probe returned no embeddings — check model name and API key');\n }\n\n return response.data[0].embedding.length;\n }\n\n async embed(text: string): Promise<number[]> {\n const normalized = normalizeText(text);\n const hash = textHash(normalized);\n const cached = cache.get(hash);\n if (cached) return cached;\n\n const body: Record<string, unknown> = {\n model: this.config.model,\n input: normalized,\n };\n if (this.config.requestedDimensions) {\n body.dimensions = this.config.requestedDimensions;\n }\n\n const response = await fetchWithRetry(\n `${this.config.baseUrl}/embeddings`,\n this.config.apiKey,\n body,\n );\n\n const embedding = response.data[0].embedding;\n if (embedding.length !== this.dimensions) {\n throw new Error(`Expected ${this.dimensions}d, got ${embedding.length}d — dimension mismatch`);\n }\n\n this.trackUsage(response);\n cacheSet(hash, embedding);\n scheduleDiskSave();\n return embedding;\n }\n\n async embedBatch(texts: string[]): Promise<number[][]> {\n const normalizedTexts = texts.map(normalizeText);\n const results: number[][] = new Array(texts.length);\n const uncachedIndices: number[] = [];\n const uncachedTexts: string[] = [];\n\n // Check cache for each text\n for (let i = 0; i < normalizedTexts.length; i++) {\n const hash = textHash(normalizedTexts[i]);\n const cached = cache.get(hash);\n if (cached) {\n results[i] = cached;\n } else {\n uncachedIndices.push(i);\n uncachedTexts.push(normalizedTexts[i]);\n }\n }\n\n if (uncachedTexts.length === 0) return results;\n\n const cacheHitRate = ((texts.length - uncachedTexts.length) / texts.length * 100).toFixed(1);\n console.error(\n `[memorix] API embedding ${uncachedTexts.length}/${texts.length} texts (cache hit: ${cacheHitRate}%)`,\n );\n\n // Split into chunks of MAX_BATCH_SIZE, then process up to MAX_CONCURRENCY in parallel\n const chunks: { texts: string[]; indices: number[] }[] = [];\n for (let batchStart = 0; batchStart < uncachedTexts.length; batchStart += MAX_BATCH_SIZE) {\n chunks.push({\n texts: uncachedTexts.slice(batchStart, batchStart + MAX_BATCH_SIZE),\n indices: uncachedIndices.slice(batchStart, batchStart + MAX_BATCH_SIZE),\n });\n }\n\n // Process chunks with bounded concurrency (competitors do sequential)\n for (let ci = 0; ci < chunks.length; ci += MAX_CONCURRENCY) {\n const concurrentChunks = chunks.slice(ci, ci + MAX_CONCURRENCY);\n const batchStartOffset = ci * MAX_BATCH_SIZE;\n\n await Promise.all(concurrentChunks.map(async (chunk, chunkIdx) => {\n const body: Record<string, unknown> = {\n model: this.config.model,\n input: chunk.texts,\n };\n if (this.config.requestedDimensions) {\n body.dimensions = this.config.requestedDimensions;\n }\n\n const response = await fetchWithRetry(\n `${this.config.baseUrl}/embeddings`,\n this.config.apiKey,\n body,\n );\n\n this.trackUsage(response);\n\n const globalChunkStart = batchStartOffset + chunkIdx * MAX_BATCH_SIZE;\n\n // API may return results in any order — use the index field\n for (const item of response.data) {\n const originalIdx = chunk.indices[item.index];\n results[originalIdx] = item.embedding;\n cacheSet(textHash(uncachedTexts[globalChunkStart + item.index]), item.embedding);\n }\n }));\n }\n\n scheduleDiskSave();\n return results;\n }\n\n /**\n * Get usage stats for logging/debugging.\n */\n getStats(): { totalTokens: number; totalApiCalls: number; cacheSize: number } {\n return {\n totalTokens: this.totalTokensUsed,\n totalApiCalls: this.totalApiCalls,\n cacheSize: cache.size,\n };\n }\n\n private trackUsage(response: EmbeddingAPIResponse): void {\n this.totalApiCalls++;\n if (response.usage) {\n this.totalTokensUsed += response.usage.total_tokens;\n }\n }\n}\n\n// ─── HTTP with Retry ─────────────────────────────────────────────────\n\n/**\n * Fetch with exponential backoff retry.\n * Handles 429 (rate limit) and 5xx (server errors) gracefully.\n */\nasync function fetchWithRetry(\n url: string,\n apiKey: string,\n body: Record<string, unknown>,\n attempt = 0,\n): Promise<EmbeddingAPIResponse> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10_000);\n let response: Response;\n try {\n response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${apiKey}`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } catch (err: unknown) {\n clearTimeout(timeout);\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error(`Embedding API timeout after 10s: ${url}`);\n }\n throw err;\n }\n clearTimeout(timeout);\n\n if (response.ok) {\n return response.json() as Promise<EmbeddingAPIResponse>;\n }\n\n // Retry on rate limit (429) or server errors (5xx)\n if ((response.status === 429 || response.status >= 500) && attempt < MAX_RETRIES) {\n const delay = BASE_DELAY_MS * Math.pow(2, attempt);\n const retryAfter = response.headers.get('retry-after');\n const waitMs = retryAfter ? parseInt(retryAfter, 10) * 1000 : delay;\n console.error(`[memorix] Embedding API ${response.status}, retry ${attempt + 1}/${MAX_RETRIES} in ${waitMs}ms`);\n await new Promise(resolve => setTimeout(resolve, waitMs));\n return fetchWithRetry(url, apiKey, body, attempt + 1);\n }\n\n const errorText = await response.text().catch(() => 'unknown error');\n throw new Error(`Embedding API error (${response.status}): ${errorText}`);\n}\n","/**\n * Embedding Provider — Abstraction Layer\n *\n * Extensible embedding interface. **Disabled by default** to minimize resource usage.\n *\n * Environment variable MEMORIX_EMBEDDING controls which provider to use:\n * - MEMORIX_EMBEDDING=off (default) → no embedding, BM25 fulltext search only (~50MB RAM)\n * - MEMORIX_EMBEDDING=fastembed → local ONNX inference (384-dim bge-small, ~300MB RAM)\n * - MEMORIX_EMBEDDING=transformers → pure JS WASM inference (384-dim MiniLM, ~500MB RAM)\n * - MEMORIX_EMBEDDING=api → remote API via OpenAI-compatible /v1/embeddings (zero local RAM)\n * - MEMORIX_EMBEDDING=auto → try fastembed → transformers → off (legacy behavior)\n *\n * API mode env vars (MEMORIX_EMBEDDING=api):\n * - MEMORIX_EMBEDDING_API_KEY → API key (fallback: MEMORIX_LLM_API_KEY → OPENAI_API_KEY)\n * - MEMORIX_EMBEDDING_BASE_URL → base URL (fallback: MEMORIX_LLM_BASE_URL)\n * - MEMORIX_EMBEDDING_MODEL → model (default: text-embedding-3-small)\n * - MEMORIX_EMBEDDING_DIMENSIONS → optional dimension override\n *\n * Resource impact of local embedding:\n * - First load: 90%+ CPU for 5-30 seconds (model initialization)\n * - Steady state: 300-500MB RAM (model in memory)\n * - Per-query: 10-50ms CPU (embedding generation)\n *\n * Most users don't need vector search — BM25 fulltext is sufficient for keyword matching.\n * Vector search is useful for semantic similarity (e.g., \"auth\" matches \"authentication\").\n *\n * Architecture inspired by Mem0's multi-provider embedding design.\n */\n\nexport interface EmbeddingProvider {\n /** Provider name for logging/cache keys */\n readonly name: string;\n /** Vector dimensions (e.g., 384 for bge-small) */\n readonly dimensions: number;\n /** Generate embedding for a single text */\n embed(text: string): Promise<number[]>;\n /** Generate embeddings for multiple texts (batch) */\n embedBatch(texts: string[]): Promise<number[][]>;\n}\n\n/** Singleton provider instance (null = not available) */\nlet provider: EmbeddingProvider | null = null;\nlet initPromise: Promise<EmbeddingProvider | null> | null = null;\n\n/**\n * Get configured embedding mode from environment.\n * Default is 'off' to minimize resource usage.\n */\nfunction getEmbeddingMode(): 'off' | 'fastembed' | 'transformers' | 'api' | 'auto' {\n // Unified: env vars > config.json > 'off'\n try {\n const { getEmbeddingMode: cfgMode } = require('../config.js');\n return cfgMode();\n } catch {\n // Fallback if config module not available\n const env = process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim();\n if (env === 'fastembed' || env === 'transformers' || env === 'api' || env === 'auto') return env;\n return 'off';\n }\n}\n\n/**\n * Get the embedding provider. Returns null if disabled or unavailable.\n * Lazy-initialized on first call. Concurrent callers share the same Promise.\n *\n * Controlled by MEMORIX_EMBEDDING environment variable (default: off).\n */\nexport async function getEmbeddingProvider(): Promise<EmbeddingProvider | null> {\n if (initPromise) return initPromise;\n\n initPromise = (async () => {\n const mode = getEmbeddingMode();\n\n // Explicit OFF — skip all embedding initialization\n if (mode === 'off') {\n console.error('[memorix] Embedding disabled (MEMORIX_EMBEDDING=off) — using BM25 fulltext search');\n return null;\n }\n\n // Explicit fastembed\n if (mode === 'fastembed') {\n try {\n const { FastEmbedProvider } = await import('./fastembed-provider.js');\n provider = await FastEmbedProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch (e) {\n console.error(`[memorix] Failed to load fastembed: ${e instanceof Error ? e.message : e}`);\n console.error('[memorix] Install with: npm install fastembed');\n return null;\n }\n }\n\n // Explicit transformers\n if (mode === 'transformers') {\n try {\n const { TransformersProvider } = await import('./transformers-provider.js');\n provider = await TransformersProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch (e) {\n console.error(`[memorix] Failed to load transformers: ${e instanceof Error ? e.message : e}`);\n console.error('[memorix] Install with: npm install @huggingface/transformers');\n return null;\n }\n }\n\n // API mode: remote embedding via OpenAI-compatible endpoint\n if (mode === 'api') {\n try {\n const { APIEmbeddingProvider } = await import('./api-provider.js');\n provider = await APIEmbeddingProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch (e) {\n console.error(`[memorix] Failed to init API embedding: ${e instanceof Error ? e.message : e}`);\n return null;\n }\n }\n\n // Auto mode: try fastembed → transformers → off (legacy behavior)\n try {\n const { FastEmbedProvider } = await import('./fastembed-provider.js');\n provider = await FastEmbedProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch {\n // fastembed not installed — try next\n }\n\n try {\n const { TransformersProvider } = await import('./transformers-provider.js');\n provider = await TransformersProvider.create();\n console.error(`[memorix] Embedding provider: ${provider!.name} (${provider!.dimensions}d)`);\n return provider;\n } catch {\n // transformers not installed — degrade to fulltext\n }\n\n console.error('[memorix] No embedding provider available — using BM25 fulltext search');\n return null;\n })();\n\n return initPromise;\n}\n\n/**\n * Check if vector search is available.\n */\nexport async function isVectorSearchAvailable(): Promise<boolean> {\n const p = await getEmbeddingProvider();\n return p !== null;\n}\n\n/**\n * Reset provider (for testing).\n */\nexport function resetProvider(): void {\n provider = null;\n initPromise = null;\n}\n","/**\n * Project Affinity Scoring\n *\n * Prevents cross-project memory pollution by scoring search results\n * based on how well they match the current project context.\n *\n * Inspired by mcp-memory-service's memory-scorer.js:\n * - High affinity: content mentions project name → full score\n * - Medium affinity: related concepts but no direct mention → 0.7x\n * - Low affinity: no project reference → 0.3x (heavily penalized)\n *\n * This runs AFTER projectId filtering, as a second layer of defense\n * against memories that were stored under the correct projectId but\n * contain content about a different project (e.g., discussing Memorix\n * development while in a test project workspace).\n */\n\nexport interface AffinityContext {\n /** Current project name (e.g., \"for_memmcp_test\", \"memorix\") */\n projectName: string;\n /** Current project ID (e.g., \"local/for_memmcp_test\", \"AVIDS2/memorix\") */\n projectId: string;\n /** Optional: keywords that indicate project relevance */\n projectKeywords?: string[];\n}\n\nexport interface MemoryContent {\n title: string;\n narrative?: string;\n facts?: string[];\n concepts?: string[];\n entityName?: string;\n filesModified?: string[];\n}\n\nexport interface AffinityResult {\n /** Affinity score 0-1 (1 = high affinity, 0 = no affinity) */\n score: number;\n /** Affinity level for debugging */\n level: 'high' | 'medium' | 'low' | 'none';\n /** Reason for the score */\n reason: string;\n}\n\n/**\n * Calculate project affinity score for a memory.\n *\n * @param memory - The memory content to evaluate\n * @param context - Current project context\n * @returns AffinityResult with score, level, and reason\n */\nexport function calculateProjectAffinity(\n memory: MemoryContent,\n context: AffinityContext,\n): AffinityResult {\n const projectName = context.projectName.toLowerCase();\n const projectId = context.projectId.toLowerCase();\n \n // Extract base name from projectId (e.g., \"memorix\" from \"AVIDS2/memorix\")\n const projectBaseName = projectId.split('/').pop() ?? projectName;\n \n // Build searchable content string\n const contentParts = [\n memory.title,\n memory.narrative ?? '',\n memory.entityName ?? '',\n ...(memory.facts ?? []),\n ...(memory.concepts ?? []),\n ...(memory.filesModified ?? []),\n ];\n const content = contentParts.join(' ').toLowerCase();\n \n // Check for direct project name mention\n if (content.includes(projectName) || content.includes(projectBaseName)) {\n return { score: 1.0, level: 'high', reason: 'project_name_in_content' };\n }\n \n // Check for project keywords (if provided)\n if (context.projectKeywords && context.projectKeywords.length > 0) {\n const keywordsLower = context.projectKeywords.map(k => k.toLowerCase());\n const matchedKeywords = keywordsLower.filter(k => content.includes(k));\n if (matchedKeywords.length >= 2) {\n return { score: 0.9, level: 'high', reason: `keywords_matched: ${matchedKeywords.join(', ')}` };\n }\n if (matchedKeywords.length === 1) {\n return { score: 0.7, level: 'medium', reason: `keyword_matched: ${matchedKeywords[0]}` };\n }\n }\n \n // Check for file paths that suggest project relevance\n const files = memory.filesModified ?? [];\n if (files.some(f => f.toLowerCase().includes(projectName) || f.toLowerCase().includes(projectBaseName))) {\n return { score: 0.85, level: 'high', reason: 'project_in_file_path' };\n }\n \n // Check entity name\n if (memory.entityName) {\n const entityLower = memory.entityName.toLowerCase();\n if (entityLower.includes(projectName) || entityLower.includes(projectBaseName)) {\n return { score: 0.8, level: 'high', reason: 'project_in_entity' };\n }\n }\n \n // Check concepts for project-related terms\n const concepts = memory.concepts ?? [];\n if (concepts.some(c => c.toLowerCase().includes(projectName) || c.toLowerCase().includes(projectBaseName))) {\n return { score: 0.75, level: 'medium', reason: 'project_in_concepts' };\n }\n \n // No project reference found — this memory might be about a different project\n // Apply penalty but don't completely filter (might still be relevant)\n return { score: 0.3, level: 'low', reason: 'no_project_reference' };\n}\n\n/**\n * Apply project affinity scoring to search results.\n *\n * @param results - Search results with scores\n * @param memories - Full memory content for each result (keyed by ID)\n * @param context - Current project context\n * @param options - Scoring options\n * @returns Results with adjusted scores, sorted by affinity-weighted score\n */\nexport function applyProjectAffinity<T extends { id: number; score: number }>(\n results: T[],\n memories: Map<number, MemoryContent>,\n context: AffinityContext,\n options: {\n /** Minimum affinity score to include (default: 0, include all) */\n minAffinity?: number;\n /** Whether to filter out low-affinity results entirely (default: false) */\n filterLowAffinity?: boolean;\n } = {},\n): T[] {\n const { minAffinity = 0, filterLowAffinity = false } = options;\n \n // Calculate affinity for each result\n const withAffinity = results.map(result => {\n const memory = memories.get(result.id);\n if (!memory) {\n // No memory content available — assume medium affinity\n return { ...result, affinity: 0.5, affinityLevel: 'medium' as const };\n }\n \n const { score: affinityScore, level } = calculateProjectAffinity(memory, context);\n return {\n ...result,\n score: result.score * affinityScore, // Apply affinity as multiplier\n affinity: affinityScore,\n affinityLevel: level,\n };\n });\n \n // Filter by minimum affinity if requested\n let filtered = withAffinity;\n if (filterLowAffinity) {\n filtered = withAffinity.filter(r => r.affinity >= 0.5);\n } else if (minAffinity > 0) {\n filtered = withAffinity.filter(r => r.affinity >= minAffinity);\n }\n \n // Re-sort by affinity-weighted score\n filtered.sort((a, b) => b.score - a.score);\n \n // Return without the extra affinity fields (keep original shape)\n return filtered.map(({ affinity: _, affinityLevel: __, ...rest }) => rest as T);\n}\n\n/**\n * Extract project keywords from project name and common patterns.\n * Used to improve affinity detection for projects with distinctive names.\n */\nexport function extractProjectKeywords(projectName: string, projectId: string): string[] {\n const keywords: string[] = [projectName];\n \n // Add base name from projectId\n const baseName = projectId.split('/').pop();\n if (baseName && baseName !== projectName) {\n keywords.push(baseName);\n }\n \n // Add common variations\n const variations = [\n projectName.replace(/-/g, '_'),\n projectName.replace(/_/g, '-'),\n projectName.replace(/[_-]/g, ''),\n ];\n for (const v of variations) {\n if (v !== projectName && !keywords.includes(v)) {\n keywords.push(v);\n }\n }\n \n return keywords.filter(k => k.length > 2);\n}\n","/**\n * Intent-Aware Recall — Query Intent Detection\n *\n * Detects the underlying intent of a search query (why/when/how/what)\n * and returns type-specific boosting factors to improve recall precision.\n *\n * Inspired by MemCP's intent routing architecture.\n * Uses fast keyword/pattern matching (no LLM needed).\n */\n\nimport type { ObservationType } from '../types.js';\n\n// ─── Types ───\n\nexport type QueryIntent = 'why' | 'when' | 'how' | 'what_changed' | 'problem' | 'general';\n\nexport interface IntentResult {\n /** Detected intent category */\n intent: QueryIntent;\n /** Confidence score 0-1 */\n confidence: number;\n /** Observation type → boost multiplier (applied to search scores) */\n typeBoosts: Partial<Record<ObservationType, number>>;\n /** Field weight overrides for Orama search (optional) */\n fieldBoosts?: Record<string, number>;\n /** Whether to prefer chronological ordering over relevance */\n preferChronological: boolean;\n}\n\n// ─── Intent Patterns ───\n\ninterface IntentPattern {\n intent: QueryIntent;\n patterns: RegExp[];\n /** Higher weight = stronger match when multiple intents match */\n weight: number;\n}\n\nconst INTENT_PATTERNS: IntentPattern[] = [\n {\n intent: 'why',\n patterns: [\n /\\bwhy\\b/i,\n /\\breason(?:s|ing)?\\b/i,\n /\\brationale\\b/i,\n /\\bmotivat(?:ion|ed)\\b/i,\n /\\bjustif(?:y|ication)\\b/i,\n /\\bchose|chosen|picked\\b/i,\n /\\bdecid(?:e[ds]?|ing)\\b/i,\n /\\btrade-?off\\b/i,\n /为什么/,\n /原因/,\n /理由/,\n /为何/,\n ],\n weight: 1.0,\n },\n {\n intent: 'when',\n patterns: [\n /\\bwhen\\b/i,\n /\\btimeline\\b/i,\n /\\bhistory\\b/i,\n /\\blast\\s+(week|month|time|session)\\b/i,\n /\\brecent(?:ly)?\\b/i,\n /\\byesterday\\b/i,\n /\\btoday\\b/i,\n /\\bchronolog/i,\n /什么时候/,\n /何时/,\n /最近/,\n /上次/,\n ],\n weight: 0.9,\n },\n {\n intent: 'how',\n patterns: [\n /\\bhow\\s+(does|do|to|is|can|did|should|would)\\b/i,\n /\\barchitecture\\b/i,\n /\\bmechanism\\b/i,\n /\\bimplement(?:ation|ed|ing)?\\b/i,\n /\\bwork(?:s|ing|ed)?\\b/i,\n /\\bexplain\\b/i,\n /\\bunderstand\\b/i,\n /怎么/,\n /如何/,\n /机制/,\n /原理/,\n /架构/,\n ],\n weight: 0.85,\n },\n {\n intent: 'what_changed',\n patterns: [\n /\\bwhat\\s+changed\\b/i,\n /\\bwhat\\s+was\\s+(modified|updated|changed)\\b/i,\n /\\bdiff(?:erence)?\\b/i,\n /\\bchangelog\\b/i,\n /\\bmodifi(?:ed|cation)\\b/i,\n /\\bupdat(?:e[ds]?|ing)\\b/i,\n /\\brefactor(?:ed|ing)?\\b/i,\n /改了/,\n /修改/,\n /变更/,\n /变化/,\n ],\n weight: 0.8,\n },\n {\n intent: 'problem',\n patterns: [\n /\\bbug(?:s|gy)?\\b/i,\n /\\berror(?:s)?\\b/i,\n /\\bfix(?:e[ds]|ing)?\\b/i,\n /\\bissue(?:s)?\\b/i,\n /\\bproblem(?:s)?\\b/i,\n /\\bcrash(?:e[ds]|ing)?\\b/i,\n /\\bfail(?:e[ds]|ure|ing)?\\b/i,\n /\\bbroken\\b/i,\n /\\bgotcha\\b/i,\n /\\bpitfall\\b/i,\n /\\bworkaround\\b/i,\n /\\btroubleshoot/i,\n /\\bdebug(?:ging)?\\b/i,\n /报错/,\n /问题/,\n /修复/,\n /故障/,\n /异常/,\n ],\n weight: 0.9,\n },\n];\n\n// ─── Type Boost Maps ───\n\nconst INTENT_TYPE_BOOSTS: Record<QueryIntent, Partial<Record<ObservationType, number>>> = {\n why: {\n 'decision': 3.0,\n 'why-it-exists': 3.0,\n 'trade-off': 2.5,\n 'how-it-works': 1.2,\n },\n when: {\n // Temporal queries don't strongly prefer any type — they prefer recency\n 'what-changed': 1.5,\n 'session-request': 1.3,\n },\n how: {\n 'how-it-works': 3.0,\n 'discovery': 2.0,\n 'decision': 1.3,\n },\n what_changed: {\n 'what-changed': 3.0,\n 'discovery': 1.5,\n 'session-request': 1.2,\n },\n problem: {\n 'problem-solution': 3.0,\n 'gotcha': 2.5,\n 'discovery': 1.3,\n },\n general: {\n // No special boosting\n },\n};\n\nconst INTENT_FIELD_BOOSTS: Partial<Record<QueryIntent, Record<string, number>>> = {\n why: {\n title: 2,\n entityName: 1.5,\n narrative: 2.5, // WHY queries need narrative context\n facts: 1.5,\n concepts: 1,\n filesModified: 0.3,\n },\n problem: {\n title: 3,\n entityName: 2,\n narrative: 2,\n facts: 2, // Bug details often in facts\n concepts: 1,\n filesModified: 1.5, // File paths help find the right bug fix\n },\n};\n\n// ─── Detection ───\n\n/**\n * Detect the intent of a search query.\n *\n * Returns the best matching intent with confidence score and\n * type-specific boosting factors to apply during search.\n */\nexport function detectQueryIntent(query: string): IntentResult {\n if (!query || query.length < 2) {\n return {\n intent: 'general',\n confidence: 0,\n typeBoosts: {},\n preferChronological: false,\n };\n }\n\n let bestIntent: QueryIntent = 'general';\n let bestScore = 0;\n let totalMatches = 0;\n\n for (const { intent, patterns, weight } of INTENT_PATTERNS) {\n let matchCount = 0;\n for (const pattern of patterns) {\n if (pattern.test(query)) matchCount++;\n }\n if (matchCount > 0) {\n const score = matchCount * weight;\n totalMatches += matchCount;\n if (score > bestScore) {\n bestScore = score;\n bestIntent = intent;\n }\n }\n }\n\n // Confidence: how strongly did we match vs. random noise\n const confidence = totalMatches === 0\n ? 0\n : Math.min(1, bestScore / 2); // 2+ pattern matches → high confidence\n\n return {\n intent: bestIntent,\n confidence,\n typeBoosts: INTENT_TYPE_BOOSTS[bestIntent],\n fieldBoosts: INTENT_FIELD_BOOSTS[bestIntent],\n preferChronological: bestIntent === 'when',\n };\n}\n\n/**\n * Apply intent-based type boosting to a search result's score.\n *\n * @param score Original search score\n * @param type Observation type of the result\n * @param intentResult Detected intent from detectQueryIntent()\n * @returns Boosted score\n */\nexport function applyIntentBoost(\n score: number,\n type: string,\n intentResult: IntentResult,\n): number {\n if (intentResult.confidence < 0.3) return score; // Low confidence → no boost\n const boost = intentResult.typeBoosts[type as ObservationType] ?? 1.0;\n // Scale boost by confidence: full boost at confidence=1, partial at lower\n const effectiveBoost = 1 + (boost - 1) * intentResult.confidence;\n return score * effectiveBoost;\n}\n","/**\n * Project Alias Registry\n *\n * Solves the \"project identity split\" problem: the same project gets different\n * projectIds depending on which IDE detects it (git remote vs local path vs placeholder).\n *\n * Maintains a registry file (~/.memorix/data/.project-aliases.json) that groups\n * all known IDs for the same physical project under one canonical ID.\n *\n * Canonical ID priority: git remote > local > placeholder\n *\n * Matching heuristics (any match → same project):\n * 1. Same normalized rootPath\n * 2. Same git remote URL\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport type { ProjectInfo } from '../types.js';\n\nconst DEFAULT_DATA_DIR = process.env.MEMORIX_DATA_DIR || path.join(os.homedir(), '.memorix', 'data');\nconst ALIAS_FILE = '.project-aliases.json';\n\n/** A group of project IDs that all refer to the same physical project */\nexport interface AliasGroup {\n /** The best-known ID for this project (git remote > local > placeholder) */\n canonical: string;\n /** All known IDs including canonical */\n aliases: string[];\n /** All known root paths (normalized) for this project */\n rootPaths: string[];\n /** Git remote URL if known */\n gitRemote?: string;\n}\n\ninterface AliasRegistry {\n version: 1;\n groups: AliasGroup[];\n}\n\n/** In-memory cache of the registry */\nlet registryCache: AliasRegistry | null = null;\nlet registryDir: string | null = null;\n\n/**\n * Normalize a root path for comparison.\n * - Forward slashes\n * - Lowercase on Windows\n * - No trailing slash\n */\nfunction normalizePath(p: string): string {\n let normalized = p.replace(/\\\\/g, '/').replace(/\\/+$/, '');\n if (process.platform === 'win32') {\n normalized = normalized.toLowerCase();\n }\n return normalized;\n}\n\n/**\n * Determine the priority of a project ID prefix.\n * Higher = better canonical candidate.\n */\nfunction idPriority(id: string): number {\n if (id.startsWith('placeholder/')) return 0;\n if (id.startsWith('local/')) return 1;\n // Git remote-based IDs (e.g., \"user/repo\") have no prefix → highest priority\n return 2;\n}\n\n/**\n * Get the alias registry file path.\n */\nfunction getRegistryPath(baseDir?: string): string {\n return path.join(baseDir ?? registryDir ?? DEFAULT_DATA_DIR, ALIAS_FILE);\n}\n\n/**\n * Load the alias registry from disk.\n */\nasync function loadRegistry(baseDir?: string): Promise<AliasRegistry> {\n if (registryCache) return registryCache;\n try {\n const data = await fs.readFile(getRegistryPath(baseDir), 'utf-8');\n const parsed = JSON.parse(data);\n if (parsed.version === 1 && Array.isArray(parsed.groups)) {\n registryCache = parsed;\n return registryCache!;\n }\n } catch { /* file doesn't exist yet */ }\n registryCache = { version: 1, groups: [] };\n return registryCache;\n}\n\n/**\n * Save the alias registry to disk.\n */\nasync function saveRegistry(baseDir?: string): Promise<void> {\n if (!registryCache) return;\n const filePath = getRegistryPath(baseDir);\n await fs.mkdir(path.dirname(filePath), { recursive: true });\n await fs.writeFile(filePath, JSON.stringify(registryCache, null, 2), 'utf-8');\n}\n\n/**\n * Find an existing alias group that matches the given project info.\n *\n * Match criteria (any one is sufficient):\n * 1. Group already contains this exact ID\n * 2. Group has a matching normalized rootPath\n * 3. Group has a matching gitRemote\n */\nfunction findMatchingGroup(\n registry: AliasRegistry,\n projectInfo: ProjectInfo,\n): AliasGroup | null {\n const normalizedRoot = normalizePath(projectInfo.rootPath);\n\n for (const group of registry.groups) {\n // Match by ID\n if (group.aliases.includes(projectInfo.id)) return group;\n\n // Match by rootPath\n if (group.rootPaths.some((rp) => rp === normalizedRoot)) return group;\n\n // Match by git remote\n if (projectInfo.gitRemote && group.gitRemote && group.gitRemote === projectInfo.gitRemote) {\n return group;\n }\n }\n\n return null;\n}\n\n/**\n * Select the best canonical ID from a list of aliases.\n * Priority: git remote-based > local > placeholder\n */\nfunction selectCanonical(aliases: string[]): string {\n return [...aliases].sort((a, b) => idPriority(b) - idPriority(a))[0];\n}\n\n/**\n * Register a detected project in the alias registry.\n *\n * If the project matches an existing group, merges the new ID/rootPath into it.\n * If not, creates a new group.\n *\n * Returns the **canonical** project ID that should be used for storage and search.\n *\n * @param projectInfo - The detected project info from detectProject()\n * @param baseDir - Override data directory (for testing)\n * @returns The canonical project ID\n */\nexport async function registerAlias(projectInfo: ProjectInfo, baseDir?: string): Promise<string> {\n const registry = await loadRegistry(baseDir);\n const normalizedRoot = normalizePath(projectInfo.rootPath);\n\n const existingGroup = findMatchingGroup(registry, projectInfo);\n\n if (existingGroup) {\n // Merge into existing group\n let changed = false;\n\n if (!existingGroup.aliases.includes(projectInfo.id)) {\n existingGroup.aliases.push(projectInfo.id);\n changed = true;\n }\n\n if (!existingGroup.rootPaths.includes(normalizedRoot)) {\n existingGroup.rootPaths.push(normalizedRoot);\n changed = true;\n }\n\n if (projectInfo.gitRemote && !existingGroup.gitRemote) {\n existingGroup.gitRemote = projectInfo.gitRemote;\n changed = true;\n }\n\n // Re-evaluate canonical (maybe we just learned a git remote ID)\n const newCanonical = selectCanonical(existingGroup.aliases);\n if (newCanonical !== existingGroup.canonical) {\n existingGroup.canonical = newCanonical;\n changed = true;\n }\n\n if (changed) {\n await saveRegistry(baseDir);\n }\n\n return existingGroup.canonical;\n }\n\n // Create new group\n const newGroup: AliasGroup = {\n canonical: projectInfo.id,\n aliases: [projectInfo.id],\n rootPaths: [normalizedRoot],\n ...(projectInfo.gitRemote ? { gitRemote: projectInfo.gitRemote } : {}),\n };\n registry.groups.push(newGroup);\n await saveRegistry(baseDir);\n\n return newGroup.canonical;\n}\n\n/**\n * Resolve all known aliases for a project ID.\n *\n * Used in search to expand the projectId filter so that observations stored\n * under any alias are found regardless of which IDE stored them.\n *\n * @returns Array of all known IDs for the same project, or [projectId] if no aliases found.\n */\nexport async function resolveAliases(projectId: string, baseDir?: string): Promise<string[]> {\n const registry = await loadRegistry(baseDir);\n\n for (const group of registry.groups) {\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\n return [...group.aliases];\n }\n }\n\n return [projectId];\n}\n\n/**\n * Get the canonical ID for a project ID.\n *\n * @returns The canonical ID, or the input ID if no alias group found.\n */\nexport async function getCanonicalId(projectId: string, baseDir?: string): Promise<string> {\n const registry = await loadRegistry(baseDir);\n\n for (const group of registry.groups) {\n if (group.aliases.includes(projectId) || group.canonical === projectId) {\n return group.canonical;\n }\n }\n\n return projectId;\n}\n\n/**\n * Get all alias groups (for dashboard/debug).\n */\nexport async function getAllAliasGroups(baseDir?: string): Promise<AliasGroup[]> {\n const registry = await loadRegistry(baseDir);\n return registry.groups;\n}\n\n/**\n * Auto-merge obvious alias groups by scanning existing observation projectIds.\n *\n * Detects project IDs that share the same base name but have different prefixes:\n * - placeholder/foo + local/foo → merge under the higher-priority one\n * - AVIDS2/test-repo + local/test-repo → merge under AVIDS2/test-repo\n *\n * Called once during server startup after observations are loaded.\n *\n * @param observedIds - All unique projectIds found in observations data\n * @returns Number of new merges performed\n */\nexport async function autoMergeByBaseName(\n observedIds: string[],\n baseDir?: string,\n): Promise<number> {\n if (observedIds.length <= 1) return 0;\n\n const registry = await loadRegistry(baseDir);\n\n // Group observed IDs by their base name (the part after the last /)\n const byBaseName = new Map<string, string[]>();\n for (const id of observedIds) {\n const baseName = id.split('/').pop() ?? id;\n if (!byBaseName.has(baseName)) byBaseName.set(baseName, []);\n byBaseName.get(baseName)!.push(id);\n }\n\n let mergeCount = 0;\n\n for (const [_baseName, ids] of byBaseName) {\n if (ids.length <= 1) continue;\n\n // Check if these IDs are already in the same alias group\n const existingGroups = new Set<number>();\n const ungroupedIds: string[] = [];\n\n for (const id of ids) {\n const groupIdx = registry.groups.findIndex(\n g => g.aliases.includes(id) || g.canonical === id,\n );\n if (groupIdx >= 0) {\n existingGroups.add(groupIdx);\n } else {\n ungroupedIds.push(id);\n }\n }\n\n // If all IDs are already in the same group, skip\n if (existingGroups.size <= 1 && ungroupedIds.length === 0) continue;\n\n // Merge: pick the best canonical from all IDs\n const allIdsInGroup = [...ids];\n const canonical = selectCanonical(allIdsInGroup);\n\n if (existingGroups.size > 0) {\n // Merge into the first existing group\n const primaryIdx = [...existingGroups][0];\n const primaryGroup = registry.groups[primaryIdx];\n\n // Add all IDs to primary group\n for (const id of allIdsInGroup) {\n if (!primaryGroup.aliases.includes(id)) {\n primaryGroup.aliases.push(id);\n }\n }\n\n // Absorb other existing groups into primary\n const otherIdxs = [...existingGroups].slice(1).sort((a, b) => b - a);\n for (const idx of otherIdxs) {\n const other = registry.groups[idx];\n for (const alias of other.aliases) {\n if (!primaryGroup.aliases.includes(alias)) {\n primaryGroup.aliases.push(alias);\n }\n }\n for (const rp of other.rootPaths) {\n if (!primaryGroup.rootPaths.includes(rp)) {\n primaryGroup.rootPaths.push(rp);\n }\n }\n if (other.gitRemote && !primaryGroup.gitRemote) {\n primaryGroup.gitRemote = other.gitRemote;\n }\n registry.groups.splice(idx, 1);\n }\n\n // Re-evaluate canonical\n primaryGroup.canonical = selectCanonical(primaryGroup.aliases);\n mergeCount++;\n } else {\n // All ungrouped — create new group\n registry.groups.push({\n canonical,\n aliases: allIdsInGroup,\n rootPaths: [],\n });\n mergeCount++;\n }\n }\n\n if (mergeCount > 0) {\n await saveRegistry(baseDir);\n }\n\n return mergeCount;\n}\n\n/**\n * Initialize the alias registry with a data directory.\n * Should be called once during server startup.\n */\nexport function initAliasRegistry(dataDir: string): void {\n registryDir = dataDir;\n registryCache = null; // Force reload from new location\n}\n\n/**\n * Reset the in-memory cache (for testing).\n */\nexport function resetAliasCache(): void {\n registryCache = null;\n}\n","/**\n * LLM Provider\n *\n * Abstraction layer for LLM-enhanced memory management.\n * Supports OpenAI-compatible APIs (OpenAI, Anthropic via proxy, local models).\n *\n * This is the optional \"premium\" path — Memorix works without it,\n * but with an LLM configured, memory quality approaches Mem0/Cipher level.\n */\n\nexport interface LLMConfig {\n provider: 'openai' | 'anthropic' | 'openrouter' | 'custom';\n apiKey: string;\n model?: string;\n baseUrl?: string;\n}\n\nexport interface LLMResponse {\n content: string;\n usage?: { promptTokens: number; completionTokens: number };\n}\n\n/** Provider defaults per provider type */\nconst PROVIDER_DEFAULTS: Record<string, { baseUrl: string; model: string }> = {\n openai: { baseUrl: 'https://api.openai.com/v1', model: 'gpt-4.1-nano' },\n anthropic: { baseUrl: 'https://api.anthropic.com/v1', model: 'claude-3-5-haiku-latest' },\n openrouter: { baseUrl: 'https://openrouter.ai/api/v1', model: 'openai/gpt-4.1-nano' },\n custom: { baseUrl: 'http://localhost:11434/v1', model: 'llama3' },\n};\n\nlet currentConfig: LLMConfig | null = null;\n\n/**\n * Initialize the LLM provider from environment variables.\n * Returns null if no API key is configured — Memorix gracefully degrades.\n */\nexport function initLLM(): LLMConfig | null {\n // Unified config: env vars > config.json > defaults\n const { getLLMApiKey, getLLMProvider, getLLMModel, getLLMBaseUrl } = require('../config.js');\n\n const apiKey = getLLMApiKey();\n if (!apiKey) {\n currentConfig = null;\n return null;\n }\n\n const provider = getLLMProvider() as LLMConfig['provider'];\n const defaults = PROVIDER_DEFAULTS[provider] ?? PROVIDER_DEFAULTS.openai;\n\n currentConfig = {\n provider,\n apiKey,\n model: getLLMModel(defaults.model),\n baseUrl: getLLMBaseUrl(defaults.baseUrl),\n };\n\n return currentConfig;\n}\n\n/**\n * Check if LLM is available.\n */\nexport function isLLMEnabled(): boolean {\n return currentConfig !== null;\n}\n\n/**\n * Get current LLM config (for display/debug).\n */\nexport function getLLMConfig(): LLMConfig | null {\n return currentConfig;\n}\n\n/**\n * Call the LLM with a prompt.\n * Uses OpenAI-compatible chat completions API (works with OpenRouter, Ollama, etc.)\n *\n * For Anthropic, we use their Messages API directly.\n */\nexport async function callLLM(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n if (!currentConfig) {\n throw new Error('LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY.');\n }\n\n if (currentConfig.provider === 'anthropic') {\n return callAnthropic(systemPrompt, userMessage);\n }\n\n return callOpenAICompatible(systemPrompt, userMessage);\n}\n\n/**\n * OpenAI-compatible API call (works with OpenAI, OpenRouter, Ollama, etc.)\n */\nasync function callOpenAICompatible(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n const config = currentConfig!;\n // Auto-fix: append /v1 if baseUrl doesn't end with it (common user mistake)\n let base = config.baseUrl!.replace(/\\/+$/, '');\n if (!base.endsWith('/v1')) base += '/v1';\n const url = `${base}/chat/completions`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${config.apiKey}`,\n },\n body: JSON.stringify({\n model: config.model,\n messages: [\n { role: 'system', content: systemPrompt },\n { role: 'user', content: userMessage },\n ],\n temperature: 0.1,\n max_tokens: 1024,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text().catch(() => 'unknown error');\n throw new Error(`LLM API error (${response.status}): ${error}`);\n }\n\n const data = await response.json() as {\n choices: Array<{ message: { content: string } }>;\n usage?: { prompt_tokens: number; completion_tokens: number };\n };\n\n return {\n content: data.choices[0]?.message?.content ?? '',\n usage: data.usage ? {\n promptTokens: data.usage.prompt_tokens,\n completionTokens: data.usage.completion_tokens,\n } : undefined,\n };\n}\n\n/**\n * Anthropic Messages API call.\n */\nasync function callAnthropic(\n systemPrompt: string,\n userMessage: string,\n): Promise<LLMResponse> {\n const config = currentConfig!;\n const url = `${config.baseUrl}/messages`;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': config.apiKey,\n 'anthropic-version': '2023-06-01',\n },\n body: JSON.stringify({\n model: config.model,\n system: systemPrompt,\n messages: [\n { role: 'user', content: userMessage },\n ],\n temperature: 0.1,\n max_tokens: 1024,\n }),\n });\n\n if (!response.ok) {\n const error = await response.text().catch(() => 'unknown error');\n throw new Error(`Anthropic API error (${response.status}): ${error}`);\n }\n\n const data = await response.json() as {\n content: Array<{ text: string }>;\n usage?: { input_tokens: number; output_tokens: number };\n };\n\n return {\n content: data.content[0]?.text ?? '',\n usage: data.usage ? {\n promptTokens: data.usage.input_tokens,\n completionTokens: data.usage.output_tokens,\n } : undefined,\n };\n}\n","/**\n * LLM Quality Enhancements\n *\n * Premium memory quality features powered by LLM:\n * 1. Narrative Compression — compress verbose narratives into concise core knowledge\n * 2. Search Reranking — rerank search results by relevance to current task context\n *\n * Both features gracefully degrade: when LLM is not configured, they return\n * the original data unchanged.\n *\n * Performance targets:\n * - Compression: ~60% token reduction per stored memory\n * - Reranking: ~40% improvement in Top-5 precision\n */\n\nimport { callLLM, isLLMEnabled } from './provider.js';\n\n// ── Narrative Compression ────────────────────────────────────────\n\nconst COMPRESS_PROMPT = `You are a memory compression engine for a coding assistant.\n\nCompress the given narrative into the shortest possible form that preserves ALL technical facts.\n\nRules:\n- Aggressively remove: filler words, background context, debugging journey, repeated info\n- Compress to MINIMUM viable length — aim for 50% or less of original\n- Keep ONLY: specific values, file paths, error messages, version numbers, config keys, causal relationships\n- Merge related points into single dense sentences\n- If facts are provided separately, do NOT repeat them in the compressed narrative\n- Output the compressed text ONLY, no explanation or wrapper\n\nExamples:\nInput: \"我在调试过程中发现JWT token的refresh机制存在问题,具体来说是因为服务端没有实现自动续签,导致用户在24小时后会遇到静默的认证失败,之前我一直以为是网络问题但后来排查发现是token过期了\"\nOutput: \"JWT refresh无自动续签→24h后静默认证失败(非网络问题)\"\n\nInput: \"Final deployment model for shadcn-blog is stable: GitHub Actions build locally, SCP artifacts to VPS, systemd manages the process. Docker was considered but rejected due to complexity overhead for a simple blog. The whole pipeline takes about 2 minutes from push to live.\"\nOutput: \"shadcn-blog部署: GH Actions构建→SCP到VPS→systemd管理, 弃Docker(复杂度过高), push到上线~2min\"`;\n\n/**\n * Compress a narrative to its essential core using LLM.\n *\n * Returns the original narrative if:\n * - LLM is not enabled\n * - Narrative is already short (≤80 chars)\n * - Narrative is already concise (commands, file paths, git operations)\n * - LLM call fails\n */\nexport async function compressNarrative(\n narrative: string,\n facts?: string[],\n type?: string,\n): Promise<{ compressed: string; saved: number; usedLLM: boolean }> {\n const originalTokens = estimateTokens(narrative);\n\n // Skip compression for short narratives\n if (!isLLMEnabled() || narrative.length <= 80) {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n\n // Skip compression for already-concise content that LLM can't meaningfully compress\n if (shouldSkipCompression(narrative, type)) {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n\n try {\n const factsContext = facts && facts.length > 0\n ? `\\n\\nSeparate facts (already stored, don't repeat): ${facts.join('; ')}`\n : '';\n\n const response = await callLLM(COMPRESS_PROMPT, narrative + factsContext);\n const compressed = response.content.trim();\n\n // Sanity check: compressed should be shorter and non-empty\n if (!compressed || compressed.length >= narrative.length) {\n return { compressed: narrative, saved: 0, usedLLM: true };\n }\n\n const compressedTokens = estimateTokens(compressed);\n return {\n compressed,\n saved: originalTokens - compressedTokens,\n usedLLM: true,\n };\n } catch {\n return { compressed: narrative, saved: 0, usedLLM: false };\n }\n}\n\n// ── Search Reranking ─────────────────────────────────────────────\n\n/** Minimal search result for reranking */\nexport interface RerankCandidate {\n id: number;\n title: string;\n type: string;\n score: number;\n narrative?: string;\n}\n\nconst RERANK_PROMPT = `You are a memory relevance ranker for a coding assistant.\n\nGiven a QUERY (what the user/agent is looking for) and a list of CANDIDATE memories,\nrerank them by relevance to the query.\n\nRules:\n- Consider semantic relevance, not just keyword overlap\n- Gotchas and decisions related to the query topic should rank higher\n- Recent problem-solutions for the same component should rank higher\n- Generic or loosely related memories should rank lower\n- Output ONLY a JSON array of IDs in order of relevance (most relevant first)\n- Include ALL candidate IDs, just reorder them\n\nExample output: [42, 15, 87, 3, 21]`;\n\n/**\n * Rerank search results using LLM contextual understanding.\n *\n * Takes Orama's initial ranking and improves it by considering\n * semantic relevance to the current query/task context.\n *\n * Returns original order if LLM is not enabled or call fails.\n */\nexport async function rerankResults(\n query: string,\n candidates: RerankCandidate[],\n): Promise<{ reranked: RerankCandidate[]; usedLLM: boolean }> {\n // Skip if too few results or LLM not available\n if (!isLLMEnabled() || candidates.length <= 2) {\n return { reranked: candidates, usedLLM: false };\n }\n\n // Only rerank top-N to save LLM tokens (reranking 20+ is wasteful)\n const MAX_RERANK = 10;\n const toRerank = candidates.slice(0, MAX_RERANK);\n const rest = candidates.slice(MAX_RERANK);\n\n try {\n const candidateList = toRerank.map(c =>\n `[ID: ${c.id}] (${c.type}) ${c.title}${c.narrative ? ` — ${c.narrative.substring(0, 100)}` : ''}`,\n ).join('\\n');\n\n const response = await callLLM(RERANK_PROMPT, `QUERY: ${query}\\n\\nCANDIDATES:\\n${candidateList}`);\n\n // Parse response — handle markdown code blocks\n let content = response.content.trim();\n if (content.startsWith('```')) {\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\n }\n\n const rankedIds = JSON.parse(content) as number[];\n\n // Validate: must be an array of numbers matching our candidates\n if (!Array.isArray(rankedIds) || rankedIds.length === 0) {\n return { reranked: candidates, usedLLM: true };\n }\n\n // Build reranked list preserving original scores for display\n const idMap = new Map(toRerank.map(c => [c.id, c]));\n const reranked: RerankCandidate[] = [];\n const seen = new Set<number>();\n\n // Add IDs in LLM-reranked order\n for (const id of rankedIds) {\n const candidate = idMap.get(id);\n if (candidate && !seen.has(id)) {\n reranked.push(candidate);\n seen.add(id);\n }\n }\n\n // Add any candidates the LLM missed (safety: never lose results)\n for (const c of toRerank) {\n if (!seen.has(c.id)) {\n reranked.push(c);\n }\n }\n\n // Append non-reranked tail\n reranked.push(...rest);\n\n return { reranked, usedLLM: true };\n } catch {\n return { reranked: candidates, usedLLM: false };\n }\n}\n\n// ── Smart Compression Filtering ──────────────────────────────────\n\n/** Patterns that indicate already-concise content not worth compressing */\nconst SKIP_PATTERNS = [\n /^(?:Command|Run|Execute):\\s/i, // Shell commands\n /^(?:File|Edit|Changed):\\s/i, // File change descriptions\n /^git\\s+(?:add|commit|push|pull|log)/i, // Git operations\n /^(?:npm|npx|pnpm|yarn|bun)\\s/i, // Package manager commands\n /^(?:Remove-Item|New-Item|Set-Content)/i, // PowerShell commands\n /^[A-Za-z]:\\\\[\\w\\\\]/, // Windows file paths\n /^\\/(?:usr|home|var|etc|opt)\\//, // Unix file paths\n];\n\n/** Low-value observation types that hooks auto-capture (usually already terse) */\nconst LOW_COMPRESSION_TYPES = new Set(['what-changed', 'discovery', 'session-request']);\n\n/**\n * Determine if a narrative should skip LLM compression.\n *\n * Skip when:\n * - Content starts with command/path patterns (already structured, not prose)\n * - Type is hooks-auto-captured AND narrative is relatively short\n * - Narrative is mostly code/paths (high ratio of special chars)\n */\nfunction shouldSkipCompression(narrative: string, type?: string): boolean {\n // Skip command/path-like content\n const firstLine = narrative.split('\\n')[0];\n if (SKIP_PATTERNS.some(p => p.test(firstLine))) return true;\n\n // Skip short auto-captured observations (hooks produce terse what-changed)\n if (type && LOW_COMPRESSION_TYPES.has(type) && narrative.length < 200) return true;\n\n // Skip if narrative is mostly code/structured data (high special char ratio)\n const specialChars = (narrative.match(/[{}()\\[\\]<>:;=|\\\\\\/\\-_\\.@#$%^&*+~`\"']/g) || []).length;\n if (specialChars / narrative.length > 0.35) return true;\n\n return false;\n}\n\n// ── Utility ──────────────────────────────────────────────────────\n\n/** Rough token estimate: ~4 chars per token for English, ~2 for CJK */\nfunction estimateTokens(text: string): number {\n const cjkChars = (text.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length;\n const otherChars = text.length - cjkChars;\n return Math.ceil(cjkChars / 1.5 + otherChars / 4);\n}\n","/**\n * Orama Store\n *\n * Full-text + vector + hybrid search engine backed by Orama.\n * Source: @orama/orama (10.1K stars, <2KB, pure JS, zero deps)\n *\n * Schema designed to store Observations with all searchable fields.\n * Vector search (embeddings) will be added in P1 phase.\n */\n\nimport { create, insert, search, remove, update, count, type AnyOrama } from '@orama/orama';\nimport type { MemorixDocument, SearchOptions, IndexEntry } from '../types.js';\nimport { OBSERVATION_ICONS, type ObservationType } from '../types.js';\nimport { getEmbeddingProvider, type EmbeddingProvider } from '../embedding/provider.js';\nimport { calculateProjectAffinity, extractProjectKeywords, type AffinityContext, type MemoryContent } from './project-affinity.js';\nimport { detectQueryIntent, applyIntentBoost } from '../search/intent-detector.js';\n\nlet db: AnyOrama | null = null;\nlet embeddingEnabled = false;\n\n/**\n * Initialize or return the Orama database instance.\n * Schema conditionally includes vector field based on embedding provider.\n * Graceful degradation: no provider → fulltext only, provider → hybrid.\n */\nexport async function getDb(): Promise<AnyOrama> {\n if (db) return db;\n\n // Check if embedding provider is available\n const provider = await getEmbeddingProvider();\n embeddingEnabled = provider !== null;\n\n const baseSchema = {\n id: 'string' as const,\n observationId: 'number' as const,\n entityName: 'string' as const,\n type: 'string' as const,\n title: 'string' as const,\n narrative: 'string' as const,\n facts: 'string' as const,\n filesModified: 'string' as const,\n concepts: 'string' as const,\n tokens: 'number' as const,\n createdAt: 'string' as const,\n projectId: 'string' as const,\n accessCount: 'number' as const,\n lastAccessedAt: 'string' as const,\n status: 'string' as const,\n };\n\n // Dynamic vector dimensions based on provider (384 for local, 1024+ for API)\n const dims = provider?.dimensions ?? 384;\n const schema = embeddingEnabled\n ? { ...baseSchema, embedding: `vector[${dims}]` as const }\n : baseSchema;\n\n db = await create({ schema });\n\n return db;\n}\n\n/**\n * Reset the database instance (useful for testing).\n */\nexport async function resetDb(): Promise<void> {\n db = null;\n embeddingEnabled = false;\n}\n\n/**\n * Check if embedding/vector search is active.\n */\nexport function isEmbeddingEnabled(): boolean {\n return embeddingEnabled;\n}\n\n/**\n * Generate embedding for text content using the available provider.\n * Returns null if no provider is available.\n */\nexport async function generateEmbedding(text: string): Promise<number[] | null> {\n const provider = await getEmbeddingProvider();\n if (!provider) return null;\n return provider.embed(text);\n}\n\n/**\n * Batch-generate embeddings for multiple texts.\n * Much faster than individual calls — ONNX processes batches of 64 in parallel.\n * Returns null entries for texts that fail.\n */\nexport async function batchGenerateEmbeddings(texts: string[]): Promise<(number[] | null)[]> {\n const provider = await getEmbeddingProvider();\n if (!provider || texts.length === 0) return texts.map(() => null);\n try {\n const results = await provider.embedBatch(texts);\n return results;\n } catch {\n return texts.map(() => null);\n }\n}\n\n/**\n * Insert an observation document into the store.\n */\nexport async function insertObservation(doc: MemorixDocument): Promise<void> {\n const database = await getDb();\n await insert(database, doc);\n}\n\n/**\n * Remove an observation document by its Orama internal ID.\n */\nexport async function removeObservation(oramaId: string): Promise<void> {\n const database = await getDb();\n await remove(database, oramaId);\n}\n\n/**\n * Search observations using Orama full-text search.\n * Returns L1 IndexEntry array (compact, ~50-100 tokens per result).\n *\n * Progressive Disclosure Layer 1 — adopted from claude-mem.\n */\nexport async function searchObservations(options: SearchOptions): Promise<IndexEntry[]> {\n const database = await getDb();\n\n // Resolve project aliases — safety net for observations not yet migrated to canonical ID.\n // After migration, this is typically a single-element array matching options.projectId.\n let projectIds: string[] | null = null;\n if (options.projectId) {\n try {\n const { resolveAliases } = await import('../project/aliases.js');\n projectIds = await resolveAliases(options.projectId);\n } catch {\n projectIds = [options.projectId];\n }\n }\n\n const filters: Record<string, unknown> = {};\n if (projectIds && projectIds.length === 1) {\n filters['projectId'] = projectIds[0];\n }\n // If multiple aliases exist, we skip the Orama projectId filter and post-filter instead\n if (options.type) {\n filters['type'] = options.type;\n }\n\n // Determine search mode: hybrid (with vector) or fulltext (default)\n const hasQuery = options.query && options.query.trim().length > 0;\n\n // ── Intent-Aware Recall ──────────────────────────────────────\n // Detect query intent (why/when/how/what/problem) and adjust\n // field weights and type boosting accordingly.\n const intentResult = hasQuery ? detectQueryIntent(options.query!) : null;\n\n // When post-filtering by multiple project aliases, request extra results to compensate\n const requestLimit = (projectIds && projectIds.length > 1)\n ? (options.limit ?? 20) * 3\n : (options.limit ?? 20);\n\n // Default field boosts — overridden by intent-specific boosts when detected\n const defaultBoost: Record<string, number> = {\n title: 3,\n entityName: 2,\n concepts: 1.5,\n narrative: 1,\n facts: 1,\n filesModified: 0.5,\n };\n const fieldBoost = (intentResult?.confidence ?? 0) > 0.3 && intentResult?.fieldBoosts\n ? intentResult.fieldBoosts\n : defaultBoost;\n\n let searchParams: Record<string, unknown> = {\n term: options.query,\n limit: requestLimit,\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\n // Search specific fields (not tokens, accessCount, etc.)\n properties: ['title', 'entityName', 'narrative', 'facts', 'concepts', 'filesModified'],\n // Field boosting: intent-aware or default\n boost: fieldBoost,\n // Fuzzy tolerance: allow 1-char typos for short queries, 2 for longer\n ...(hasQuery ? { tolerance: options.query!.length > 6 ? 2 : 1 } : {}),\n };\n\n // If embedding provider is available and we have a query, use hybrid search\n let queryVector: number[] | null = null;\n if (embeddingEnabled && hasQuery) {\n try {\n const provider = await getEmbeddingProvider();\n if (provider) {\n queryVector = await provider.embed(options.query!);\n // Detect CJK-heavy queries: BM25 can't tokenize Chinese/Japanese/Korean well\n const cjkRatio = (options.query!.match(/[\\u4e00-\\u9fff\\u3040-\\u309f\\u30a0-\\u30ff\\uac00-\\ud7af]/g) || []).length / options.query!.length;\n const isCJKHeavy = cjkRatio > 0.3;\n searchParams = {\n ...searchParams,\n mode: 'hybrid',\n vector: {\n value: queryVector,\n property: 'embedding',\n },\n similarity: isCJKHeavy ? 0.3 : 0.5,\n hybridWeights: isCJKHeavy\n ? { text: 0.2, vector: 0.8 } // CJK: trust vector over BM25\n : { text: 0.6, vector: 0.4 },\n };\n }\n } catch {\n // Fallback to fulltext if embedding fails\n }\n }\n\n let results = await search(database, searchParams);\n\n // Fallback: if hybrid returned nothing but we have a vector, retry with vector-only\n if (results.count === 0 && queryVector && embeddingEnabled) {\n try {\n const vectorOnlyParams: Record<string, unknown> = {\n term: '',\n limit: requestLimit,\n ...(Object.keys(filters).length > 0 ? { where: filters } : {}),\n mode: 'vector',\n vector: {\n value: queryVector,\n property: 'embedding',\n },\n similarity: 0.25,\n };\n results = await search(database, vectorOnlyParams);\n } catch {\n // Keep original empty results\n }\n }\n\n // Status filter: default to 'active' only\n const statusFilter = options.status ?? 'active';\n\n // Build intermediate results with rawTime for temporal filtering\n let intermediate = results.hits\n // Post-filter by project aliases when multiple aliases exist (Orama doesn't support `in` for strings)\n .filter((hit) => {\n if (!projectIds || projectIds.length <= 1) return true;\n const doc = hit.document as unknown as MemorixDocument;\n return projectIds.includes(doc.projectId);\n })\n // Post-filter by status (active/resolved/archived)\n .filter((hit) => {\n if (statusFilter === 'all') return true;\n const doc = hit.document as unknown as MemorixDocument;\n return (doc.status || 'active') === statusFilter;\n })\n .map((hit) => {\n const doc = hit.document as unknown as MemorixDocument;\n const obsType = doc.type as ObservationType;\n // Time decay: newer memories get higher boost\n const ageMs = Date.now() - new Date(doc.createdAt).getTime();\n const DAY = 86_400_000;\n let recencyBoost: number;\n if (ageMs < 1 * DAY) recencyBoost = 1.0;\n else if (ageMs < 7 * DAY) recencyBoost = 0.85;\n else if (ageMs < 30 * DAY) recencyBoost = 0.6;\n else recencyBoost = 0.35;\n\n return {\n id: doc.observationId,\n time: formatTime(doc.createdAt),\n rawTime: doc.createdAt,\n type: obsType,\n icon: OBSERVATION_ICONS[obsType] ?? '❓',\n title: doc.title,\n tokens: doc.tokens,\n score: (hit.score ?? 1) * recencyBoost,\n };\n });\n\n // ── Intent-Aware Type Boosting ───────────────────────────────\n // Boost scores for observation types that match the query intent\n if (intentResult && intentResult.confidence > 0.3) {\n intermediate = intermediate.map(entry => ({\n ...entry,\n score: applyIntentBoost(entry.score, entry.type, intentResult),\n }));\n }\n\n // Re-sort: chronological for WHEN queries, relevance for others\n if (intentResult?.preferChronological) {\n intermediate.sort((a, b) => new Date(b.rawTime).getTime() - new Date(a.rawTime).getTime());\n } else {\n intermediate.sort((a, b) => b.score - a.score);\n }\n\n // ─── Project Affinity Scoring (mcp-memory-service style) ───\n // Penalize memories that don't reference the current project to prevent\n // cross-project pollution (e.g., discussing Memorix in a test project workspace)\n if (options.projectId && intermediate.length > 0) {\n const projectName = options.projectId.split('/').pop() ?? options.projectId;\n const affinityContext: AffinityContext = {\n projectName,\n projectId: options.projectId,\n projectKeywords: extractProjectKeywords(projectName, options.projectId),\n };\n\n // Build a map of memory content for affinity calculation\n const memoryContentMap = new Map<number, MemoryContent>();\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n memoryContentMap.set(doc.observationId, {\n title: doc.title,\n narrative: doc.narrative,\n facts: doc.facts?.split?.('\\n') ?? (Array.isArray(doc.facts) ? doc.facts : []),\n concepts: doc.concepts?.split?.('\\n') ?? (Array.isArray(doc.concepts) ? doc.concepts : []),\n entityName: doc.entityName,\n filesModified: doc.filesModified?.split?.('\\n') ?? (Array.isArray(doc.filesModified) ? doc.filesModified : []),\n });\n }\n\n // Apply affinity scoring to each result\n intermediate = intermediate.map(entry => {\n const memory = memoryContentMap.get(entry.id);\n if (!memory) return entry;\n\n const { score: affinityScore } = calculateProjectAffinity(memory, affinityContext);\n return {\n ...entry,\n score: entry.score * affinityScore, // Apply affinity as multiplier\n };\n });\n\n // Re-sort after affinity adjustment\n intermediate.sort((a, b) => b.score - a.score);\n }\n\n // Temporal filtering: since/until date range\n if (options.since) {\n const sinceDate = new Date(options.since).getTime();\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() >= sinceDate);\n }\n if (options.until) {\n const untilDate = new Date(options.until).getTime();\n intermediate = intermediate.filter(e => new Date(e.rawTime).getTime() <= untilDate);\n }\n\n // Apply original limit after post-filtering (we requested extra when multi-alias post-filter is active)\n if (projectIds && projectIds.length > 1) {\n intermediate = intermediate.slice(0, options.limit ?? 20);\n }\n\n // ── LLM Reranking (premium quality) ────────────────────────────\n // After Orama + recency + affinity scoring, use LLM to rerank by\n // semantic relevance to the actual query context.\n // ~40% improvement in Top-5 precision when enabled.\n if (hasQuery && intermediate.length > 2) {\n try {\n const { rerankResults } = await import('../llm/quality.js');\n // Build narrative snippets from original search hits for richer reranking\n const narrativeMap = new Map<number, string>();\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n narrativeMap.set(doc.observationId, doc.narrative);\n }\n const candidates = intermediate.map(e => ({\n id: e.id,\n title: e.title,\n type: e.type,\n score: e.score,\n narrative: narrativeMap.get(e.id),\n }));\n const { reranked, usedLLM } = await rerankResults(options.query!, candidates);\n if (usedLLM) {\n // Rebuild intermediate with reranked order, preserving all original fields\n const intermediateMap = new Map(intermediate.map(e => [e.id, e]));\n const rerankedIntermediate = reranked\n .map(r => intermediateMap.get(r.id))\n .filter((e): e is NonNullable<typeof e> => e != null);\n if (rerankedIntermediate.length > 0) {\n intermediate = rerankedIntermediate;\n }\n }\n } catch { /* reranking is best-effort */ }\n }\n\n // Build IndexEntry with optional match explanation\n let entries: IndexEntry[] = intermediate.map(({ rawTime: _, ...rest }) => rest);\n\n // Explainable recall: annotate entries with match reasons (O(1) lookup via Map)\n if (hasQuery && options.query) {\n const queryLower = options.query.toLowerCase();\n const queryTokens = queryLower.split(/\\s+/).filter(t => t.length > 1);\n const entryMap = new Map(entries.map(e => [e.id, e]));\n for (const hit of results.hits) {\n const doc = hit.document as unknown as MemorixDocument;\n const entry = entryMap.get(doc.observationId);\n if (!entry) continue;\n\n const reasons: string[] = [];\n const fields: [string, string][] = [\n ['title', doc.title], ['entity', doc.entityName], ['concept', doc.concepts],\n ['narrative', doc.narrative], ['fact', doc.facts], ['file', doc.filesModified],\n ];\n for (const [name, value] of fields) {\n const valueLower = value.toLowerCase();\n if (queryTokens.some(t => valueLower.includes(t))) reasons.push(name);\n }\n if (reasons.length === 0) reasons.push('fuzzy');\n (entry as unknown as Record<string, unknown>)['matchedFields'] = reasons;\n }\n }\n\n // Apply token budget if specified (inspired by MemCP)\n if (options.maxTokens && options.maxTokens > 0) {\n entries = applyTokenBudget(entries, options.maxTokens);\n }\n\n // Record access for returned results (fire-and-forget, non-blocking)\n const hitDocs = results.hits.map((h) => ({ id: h.id, doc: h.document as unknown as MemorixDocument }));\n recordAccessBatch(hitDocs).catch(() => {});\n\n return entries;\n}\n\n/**\n * Get full observation documents by their observation IDs.\n *\n * Progressive Disclosure Layer 3 — adopted from claude-mem.\n */\nexport async function getObservationsByIds(\n ids: number[],\n projectId?: string,\n): Promise<MemorixDocument[]> {\n const database = await getDb();\n\n // Search for each ID individually and collect results\n const results: MemorixDocument[] = [];\n\n for (const id of ids) {\n const searchResult = await search(database, {\n term: '',\n where: {\n observationId: { eq: id },\n ...(projectId ? { projectId } : {}),\n },\n limit: 1,\n });\n\n if (searchResult.hits.length > 0) {\n results.push(searchResult.hits[0].document as unknown as MemorixDocument);\n }\n }\n\n return results;\n}\n\n/**\n * Get observations around an anchor for timeline context.\n *\n * Progressive Disclosure Layer 2 — adopted from claude-mem.\n */\nexport async function getTimeline(\n anchorId: number,\n _projectId?: string,\n depthBefore = 3,\n depthAfter = 3,\n): Promise<{ before: IndexEntry[]; anchor: IndexEntry | null; after: IndexEntry[] }> {\n // Use in-memory observations for reliable lookup\n // (Orama search with empty term is unreliable — same fix as compactDetail)\n const { getAllObservations } = await import('../memory/observations.js');\n const allObs = getAllObservations();\n\n // Sort by creation time\n const sorted = allObs.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n\n const anchorIndex = sorted.findIndex((o) => o.id === anchorId);\n if (anchorIndex === -1) {\n return { before: [], anchor: null, after: [] };\n }\n\n const toIndexEntry = (obs: { id: number; type: string; title: string; tokens: number; createdAt: string }): IndexEntry => {\n const obsType = obs.type as ObservationType;\n return {\n id: obs.id,\n time: formatTime(obs.createdAt),\n type: obsType,\n icon: OBSERVATION_ICONS[obsType] ?? '❓',\n title: obs.title,\n tokens: obs.tokens,\n };\n };\n\n const before = sorted\n .slice(Math.max(0, anchorIndex - depthBefore), anchorIndex)\n .map(toIndexEntry);\n\n const after = sorted\n .slice(anchorIndex + 1, anchorIndex + 1 + depthAfter)\n .map(toIndexEntry);\n\n return {\n before,\n anchor: toIndexEntry(sorted[anchorIndex]),\n after,\n };\n}\n\n/**\n * Record access for observations returned in search results.\n * Increments accessCount and updates lastAccessedAt.\n * Inspired by mcp-memory-service's record_access() pattern.\n */\nasync function recordAccessBatch(hitDocs: { id: string; doc: MemorixDocument }[]): Promise<void> {\n const database = await getDb();\n const now = new Date().toISOString();\n\n for (const { id, doc } of hitDocs) {\n try {\n // Use update() directly — no need to re-search since we already have the doc\n await update(database, id, {\n ...doc,\n accessCount: (doc.accessCount ?? 0) + 1,\n lastAccessedAt: now,\n });\n } catch {\n // Best-effort — don't break search if access tracking fails\n }\n }\n}\n\n/**\n * Trim search results to fit within a token budget.\n * Inspired by MemCP's _apply_token_budget() pattern.\n */\nfunction applyTokenBudget(entries: IndexEntry[], maxTokens: number): IndexEntry[] {\n const budgeted: IndexEntry[] = [];\n let tokensUsed = 0;\n\n for (const entry of entries) {\n if (tokensUsed + entry.tokens > maxTokens && budgeted.length > 0) {\n break;\n }\n budgeted.push(entry);\n tokensUsed += entry.tokens;\n }\n\n return budgeted;\n}\n\n/**\n * Get total observation count, optionally filtered by project.\n */\nexport async function getObservationCount(projectId?: string): Promise<number> {\n const database = await getDb();\n if (!projectId) {\n return await count(database);\n }\n const results = await search(database, {\n term: '',\n where: { projectId },\n limit: 0,\n });\n return results.count;\n}\n\n/**\n * Format ISO date string to compact time display.\n */\nfunction formatTime(isoDate: string): string {\n try {\n const date = new Date(isoDate);\n return date.toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n });\n } catch {\n return isoDate;\n }\n}\n","/**\n * Token Budget Manager\n *\n * Provides token counting and budget management for Progressive Disclosure.\n * Source: gpt-tokenizer (737 stars, JS port of OpenAI's tiktoken)\n *\n * Used by the Compact Engine to determine which layer of detail\n * fits within the caller's token budget.\n */\n\nimport { countTokens, isWithinTokenLimit } from 'gpt-tokenizer';\n\n/**\n * Count tokens in a string.\n */\nexport function countTextTokens(text: string): number {\n return countTokens(text);\n}\n\n/**\n * Check if text fits within a token limit.\n * Returns the token count if within limit, false otherwise.\n */\nexport function fitsInBudget(text: string, limit: number): number | false {\n return isWithinTokenLimit(text, limit);\n}\n\n/**\n * Truncate text to fit within a token budget.\n * Truncates at sentence boundaries when possible.\n */\nexport function truncateToTokenBudget(text: string, budget: number): string {\n if (fitsInBudget(text, budget) !== false) {\n return text;\n }\n\n // Binary search for the right length\n const sentences = text.split(/(?<=[.!?])\\s+/);\n let result = '';\n\n for (const sentence of sentences) {\n const candidate = result ? `${result} ${sentence}` : sentence;\n if (fitsInBudget(candidate, budget) === false) {\n break;\n }\n result = candidate;\n }\n\n // If no complete sentence fits, truncate by characters\n if (!result) {\n // Rough estimate: 1 token ≈ 4 chars for English, ≈ 1.5 chars for Chinese\n const estimatedChars = budget * 2;\n result = text.slice(0, estimatedChars);\n // Refine\n while (fitsInBudget(result, budget) === false && result.length > 0) {\n result = result.slice(0, Math.floor(result.length * 0.9));\n }\n if (result.length < text.length) {\n result += '...';\n }\n }\n\n return result;\n}\n\n/**\n * Estimate the token cost of an IndexEntry line.\n * Used to predict compact index size.\n */\nexport function estimateIndexEntryTokens(title: string): number {\n // Format: \"| #ID | Time | Icon | Title | ~Tokens |\"\n // Overhead is roughly 15 tokens for formatting\n return countTextTokens(title) + 15;\n}\n","/**\n * Entity Extractor\n *\n * Regex-based entity extraction from observation content.\n * Inspired by MemCP's RegexEntityExtractor (MAGMA paper).\n *\n * Extracts: file paths, module paths, URLs, @mentions, CamelCase identifiers.\n * Also detects causal patterns for automatic edge typing.\n */\n\nconst ENTITY_PATTERNS: Array<{ kind: string; pattern: RegExp }> = [\n // File paths (e.g. src/auth/jwt.ts, ./config.json)\n { kind: 'file', pattern: /(?:^|[\\s\"'(])([.\\w/-]+\\.\\w{1,10})(?:[\\s\"'),]|$)/g },\n // Module/package paths (e.g. @orama/orama, memcp.core.graph)\n { kind: 'module', pattern: /(?:^|[\\s\"'(,])(@[\\w-]+\\/[\\w.-]+)|\\b([a-zA-Z_]\\w*(?:\\.[a-zA-Z_]\\w*){2,})\\b/g },\n // URLs\n { kind: 'url', pattern: /https?:\\/\\/[^\\s\"'<>)]+/g },\n // @mentions\n { kind: 'mention', pattern: /@([a-zA-Z_]\\w+)/g },\n // CamelCase identifiers (likely class/type names)\n { kind: 'identifier', pattern: /\\b([A-Z][a-z]+(?:[A-Z][a-z]+)+)\\b/g },\n // Chinese identifiers: quoted Chinese terms or backtick-wrapped Chinese (e.g. 「认证模块」, `数据库连接`)\n { kind: 'identifier', pattern: /[「『【]([一-鿿㐀-䶿]{2,}(?:[一-鿿㐀-䶿a-zA-Z0-9_-]*[一-鿿㐀-䶿])?)[」』】]/g },\n { kind: 'identifier', pattern: /`([一-鿿㐀-䶿]{2,}[一-鿿㐀-䶿a-zA-Z0-9_-]*)`/g },\n];\n\n/**\n * Patterns that indicate causal relationships.\n * Used to auto-detect causal edge types in Knowledge Graph.\n */\nconst CAUSAL_PATTERN = /\\b(?:because|therefore|due to|caused by|as a result|decided to|chosen because|so that|in order to|leads to|results in|fixed by|resolved by)\\b|(?:因为|所以|由于|导致|造成|结果|因此|为了|解决|修复|修正|决定|选择|采用)/i;\n\nexport interface ExtractedEntities {\n files: string[];\n modules: string[];\n urls: string[];\n mentions: string[];\n identifiers: string[];\n hasCausalLanguage: boolean;\n}\n\n/**\n * Extract entities from text content.\n * Returns deduplicated lists of each entity type.\n */\nexport function extractEntities(content: string): ExtractedEntities {\n const result: ExtractedEntities = {\n files: [],\n modules: [],\n urls: [],\n mentions: [],\n identifiers: [],\n hasCausalLanguage: false,\n };\n\n const seen = new Set<string>();\n\n for (const { kind, pattern } of ENTITY_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = pattern.exec(content)) !== null) {\n const entity = (match[1] ?? match[2] ?? match[0]).trim().replace(/^[\"'(]+|[\"'),]+$/g, '');\n if (entity.length < 3 || (kind === 'file' && entity.length < 5)) continue;\n\n const key = `${kind}:${entity.toLowerCase()}`;\n if (seen.has(key)) continue;\n seen.add(key);\n\n switch (kind) {\n case 'file':\n result.files.push(entity);\n break;\n case 'module':\n result.modules.push(entity);\n break;\n case 'url':\n result.urls.push(entity);\n break;\n case 'mention':\n result.mentions.push(entity);\n break;\n case 'identifier':\n result.identifiers.push(entity);\n break;\n }\n }\n }\n\n result.hasCausalLanguage = CAUSAL_PATTERN.test(content);\n\n return result;\n}\n\n/**\n * Auto-generate concepts from extracted entities.\n * Merges with any user-provided concepts.\n */\nexport function enrichConcepts(\n userConcepts: string[],\n extracted: ExtractedEntities,\n): string[] {\n const all = new Set(userConcepts.map((c) => c.toLowerCase()));\n const enriched = [...userConcepts];\n\n // Add file names (without path) as concepts\n for (const f of extracted.files) {\n const name = f.split('/').pop()?.replace(/\\.\\w+$/, '') ?? '';\n if (name.length >= 3 && !all.has(name.toLowerCase())) {\n all.add(name.toLowerCase());\n enriched.push(name);\n }\n }\n\n // Add module names as concepts\n for (const m of extracted.modules) {\n const short = m.split(/[./]/).pop() ?? '';\n if (short.length >= 3 && !all.has(short.toLowerCase())) {\n all.add(short.toLowerCase());\n enriched.push(short);\n }\n }\n\n // Add CamelCase identifiers as concepts\n for (const id of extracted.identifiers) {\n if (!all.has(id.toLowerCase())) {\n all.add(id.toLowerCase());\n enriched.push(id);\n }\n }\n\n return enriched;\n}\n","/**\n * Observations Manager\n *\n * Manages rich observation records with auto-classification and token counting.\n * Source: claude-mem's observation data model with structured fields.\n *\n * Each observation is stored both in the knowledge graph (as entity observation)\n * and in the Orama search index (for full-text + vector search).\n */\n\nimport type { Observation, ObservationType, ObservationStatus, MemorixDocument, ProgressInfo } from '../types.js';\nimport { TOPIC_KEY_FAMILIES } from '../types.js';\nimport { insertObservation, removeObservation, resetDb, generateEmbedding, batchGenerateEmbeddings, isEmbeddingEnabled } from '../store/orama-store.js';\nimport { saveObservationsJson, loadObservationsJson, saveIdCounter, loadIdCounter } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\nimport { countTextTokens } from '../compact/token-budget.js';\nimport { extractEntities, enrichConcepts } from './entity-extractor.js';\n\n/** In-memory observation list (loaded from persistence on init) */\nlet observations: Observation[] = [];\nlet nextId = 1;\nlet projectDir: string | null = null;\n\n/**\n * Initialize the observations manager with a project directory.\n */\nexport async function initObservations(dir: string): Promise<void> {\n projectDir = dir;\n const loaded = await loadObservationsJson(dir);\n observations = loaded as Observation[];\n nextId = await loadIdCounter(dir);\n}\n\n/**\n * Store a new observation.\n *\n * This is the primary write API — called by the `memorix_store` MCP tool.\n * Automatically:\n * 1. Assigns an incremental ID\n * 2. Counts tokens for the observation content\n * 3. Inserts into Orama for full-text search\n * 4. Persists to disk\n */\nexport async function storeObservation(input: {\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n concepts?: string[];\n projectId: string;\n topicKey?: string;\n sessionId?: string;\n progress?: ProgressInfo;\n}): Promise<{ observation: Observation; upserted: boolean }> {\n const now = new Date().toISOString();\n\n // Topic key upsert: check if an observation with the same topicKey+projectId exists\n if (input.topicKey) {\n const existing = observations.find(\n o => o.topicKey === input.topicKey && o.projectId === input.projectId,\n );\n if (existing) {\n return { observation: await upsertObservation(existing, input, now), upserted: true };\n }\n }\n\n const id = nextId++;\n\n // Auto-extract entities from narrative (inspired by MemCP RegexEntityExtractor)\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const extracted = extractEntities(contentForExtraction);\n\n // Auto-enrich concepts with extracted entities\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\n\n // Auto-enrich filesModified with extracted file paths\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\n const enrichedFiles = [...(input.filesModified ?? [])];\n for (const f of extracted.files) {\n if (!userFiles.has(f.toLowerCase())) {\n enrichedFiles.push(f);\n }\n }\n\n // Count tokens for the full observation content\n const fullText = [\n input.title,\n input.narrative,\n ...(input.facts ?? []),\n ...enrichedFiles,\n ...enrichedConcepts,\n ].join(' ');\n const tokens = countTextTokens(fullText);\n\n const observation: Observation = {\n id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: input.facts ?? [],\n filesModified: enrichedFiles,\n concepts: enrichedConcepts,\n tokens,\n createdAt: now,\n projectId: input.projectId,\n hasCausalLanguage: extracted.hasCausalLanguage,\n topicKey: input.topicKey,\n revisionCount: 1,\n sessionId: input.sessionId,\n status: 'active',\n progress: input.progress,\n };\n\n observations.push(observation);\n\n // Insert into Orama search index WITHOUT embedding first (non-blocking)\n const doc: MemorixDocument = {\n id: `obs-${id}`,\n observationId: id,\n entityName: input.entityName,\n type: input.type,\n title: input.title,\n narrative: input.narrative,\n facts: (input.facts ?? []).join('\\n'),\n filesModified: enrichedFiles.join('\\n'),\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens,\n createdAt: now,\n projectId: input.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: 'active',\n };\n\n await insertObservation(doc);\n\n // Persist to disk with file lock (cross-process safe)\n if (projectDir) {\n await withFileLock(projectDir, async () => {\n // Re-read from disk to merge changes from other processes\n const diskObs = await loadObservationsJson(projectDir!) as Observation[];\n const diskNextId = await loadIdCounter(projectDir!);\n\n // Merge: add our new observation if not already present\n const existingIds = new Set(diskObs.map(o => o.id));\n if (!existingIds.has(observation.id)) {\n diskObs.push(observation);\n }\n\n // Use the higher nextId (ours or disk's)\n const mergedNextId = Math.max(nextId, diskNextId);\n\n // Update in-memory state with merged data\n observations = diskObs;\n nextId = mergedNextId;\n\n await saveObservationsJson(projectDir!, observations);\n await saveIdCounter(projectDir!, nextId);\n });\n }\n\n // Generate embedding async (fire-and-forget) — never blocks MCP response\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n generateEmbedding(searchableText).then(async (embedding) => {\n if (embedding) {\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(`obs-${id}`);\n await insertObservation(Object.assign({}, doc, { embedding }));\n } catch {\n // Embedding index update failed — observation still persisted without vector\n }\n }\n }).catch((err) => {\n console.error(`[memorix] Async embedding failed for obs-${id}: ${err instanceof Error ? err.message : err}`);\n });\n\n return { observation, upserted: false };\n}\n\n/**\n * Update an existing observation via topic key upsert.\n * Replaces content but preserves the original ID and createdAt.\n */\nasync function upsertObservation(\n existing: Observation,\n input: {\n entityName: string;\n type: ObservationType;\n title: string;\n narrative: string;\n facts?: string[];\n filesModified?: string[];\n concepts?: string[];\n projectId: string;\n topicKey?: string;\n sessionId?: string;\n progress?: ProgressInfo;\n },\n now: string,\n): Promise<Observation> {\n // Auto-extract and enrich (same as storeObservation)\n const contentForExtraction = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const extracted = extractEntities(contentForExtraction);\n const enrichedConcepts = enrichConcepts(input.concepts ?? [], extracted);\n const userFiles = new Set((input.filesModified ?? []).map((f) => f.toLowerCase()));\n const enrichedFiles = [...(input.filesModified ?? [])];\n for (const f of extracted.files) {\n if (!userFiles.has(f.toLowerCase())) enrichedFiles.push(f);\n }\n const fullText = [input.title, input.narrative, ...(input.facts ?? []), ...enrichedFiles, ...enrichedConcepts].join(' ');\n const tokens = countTextTokens(fullText);\n\n // Mark old observation as resolved (superseded by new version)\n // Note: topicKey upsert replaces in-place, so we just bump revision\n\n // Update in-place\n existing.entityName = input.entityName;\n existing.type = input.type;\n existing.title = input.title;\n existing.narrative = input.narrative;\n existing.facts = input.facts ?? [];\n existing.filesModified = enrichedFiles;\n existing.concepts = enrichedConcepts;\n existing.tokens = tokens;\n existing.updatedAt = now;\n existing.hasCausalLanguage = extracted.hasCausalLanguage;\n existing.revisionCount = (existing.revisionCount ?? 1) + 1;\n existing.status = 'active';\n if (input.sessionId) existing.sessionId = input.sessionId;\n if (input.progress) existing.progress = input.progress;\n\n // Re-index in Orama WITHOUT embedding first (non-blocking)\n const doc: MemorixDocument = {\n id: `obs-${existing.id}`,\n observationId: existing.id,\n entityName: existing.entityName,\n type: existing.type,\n title: existing.title,\n narrative: existing.narrative,\n facts: existing.facts.join('\\n'),\n filesModified: enrichedFiles.join('\\n'),\n concepts: enrichedConcepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens,\n createdAt: existing.createdAt,\n projectId: existing.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: 'active',\n };\n\n // Remove old doc and insert updated one\n try {\n const { removeObservation } = await import('../store/orama-store.js');\n await removeObservation(`obs-${existing.id}`);\n } catch { /* may not exist in index */ }\n await insertObservation(doc);\n\n // Persist\n if (projectDir) {\n await withFileLock(projectDir, async () => {\n const diskObs = await loadObservationsJson(projectDir!) as Observation[];\n const idx = diskObs.findIndex(o => o.id === existing.id);\n if (idx >= 0) {\n diskObs[idx] = existing;\n } else {\n diskObs.push(existing);\n }\n observations = diskObs;\n await saveObservationsJson(projectDir!, observations);\n });\n }\n\n // Generate embedding async (fire-and-forget) — never blocks MCP response\n const searchableText = [input.title, input.narrative, ...(input.facts ?? [])].join(' ');\n const obsId = existing.id;\n generateEmbedding(searchableText).then(async (embedding) => {\n if (embedding) {\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(`obs-${obsId}`);\n await insertObservation(Object.assign({}, doc, { embedding }));\n } catch {\n // Embedding index update failed — observation still persisted without vector\n }\n }\n }).catch((err) => {\n console.error(`[memorix] Async embedding failed for obs-${obsId}: ${err instanceof Error ? err.message : err}`);\n });\n\n return existing;\n}\n\n/**\n * Get an observation by ID.\n */\nexport function getObservation(id: number): Observation | undefined {\n return observations.find((o) => o.id === id);\n}\n\n/**\n * Resolve observations — mark them as resolved (completed/no longer active).\n * This prevents resolved memories from appearing in default search results.\n */\nexport async function resolveObservations(\n ids: number[],\n status: ObservationStatus = 'resolved',\n): Promise<{ resolved: number[]; notFound: number[] }> {\n const resolved: number[] = [];\n const notFound: number[] = [];\n const now = new Date().toISOString();\n\n for (const id of ids) {\n const obs = observations.find(o => o.id === id);\n if (!obs) {\n notFound.push(id);\n continue;\n }\n obs.status = status;\n obs.updatedAt = now;\n if (obs.progress) {\n obs.progress.status = status === 'resolved' ? 'completed' : obs.progress.status;\n }\n resolved.push(id);\n\n // Update Orama index (without blocking on embedding)\n try {\n const { removeObservation: removeObs } = await import('../store/orama-store.js');\n await removeObs(`obs-${id}`);\n const doc: MemorixDocument = {\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map(c => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status,\n };\n await insertObservation(doc);\n // Async embedding update (fire-and-forget)\n const obsId = obs.id;\n generateEmbedding([obs.title, obs.narrative, ...obs.facts].join(' ')).then(async (embedding) => {\n if (embedding) {\n try {\n await removeObs(`obs-${obsId}`);\n await insertObservation(Object.assign({}, doc, { embedding }));\n } catch { /* best effort */ }\n }\n }).catch(() => {});\n } catch { /* best effort */ }\n }\n\n // Persist\n if (projectDir && resolved.length > 0) {\n await withFileLock(projectDir, async () => {\n await saveObservationsJson(projectDir!, observations);\n });\n }\n\n return { resolved, notFound };\n}\n\n/**\n * Get all observations for a project.\n * Supports alias expansion: if projectIds is an array, matches any of them.\n */\nexport function getProjectObservations(projectId: string | string[]): Observation[] {\n if (Array.isArray(projectId)) {\n const idSet = new Set(projectId);\n return observations.filter((o) => idSet.has(o.projectId));\n }\n return observations.filter((o) => o.projectId === projectId);\n}\n\n/**\n * Migrate observations from non-canonical project IDs to the canonical ID.\n *\n * Called once during server startup after alias registration.\n * Rewrites in-memory observations and persists changes to disk.\n *\n * @param aliasIds - All known alias IDs for this project (including canonical)\n * @param canonicalId - The canonical project ID to normalize to\n * @returns Number of observations migrated\n */\nexport async function migrateProjectIds(\n aliasIds: string[],\n canonicalId: string,\n): Promise<number> {\n const nonCanonical = new Set(aliasIds.filter(id => id !== canonicalId));\n if (nonCanonical.size === 0) return 0;\n\n let migrated = 0;\n for (const obs of observations) {\n if (nonCanonical.has(obs.projectId)) {\n obs.projectId = canonicalId;\n migrated++;\n }\n }\n\n if (migrated > 0 && projectDir) {\n await withFileLock(projectDir, async () => {\n await saveObservationsJson(projectDir!, observations);\n });\n }\n\n return migrated;\n}\n\n/**\n * Get all observations (in-memory copy).\n * Used by timeline and retention to avoid unreliable Orama empty-term queries.\n */\nexport function getAllObservations(): Observation[] {\n return [...observations];\n}\n\n/**\n * Get the total number of stored observations.\n */\nexport function getObservationCount(): number {\n return observations.length;\n}\n\n/**\n * Suggest a stable topic key from type + title.\n * Uses family heuristics (architecture/*, bug/*, decision/*, etc.)\n * Inspired by Engram's mem_suggest_topic_key.\n */\nexport function suggestTopicKey(type: string, title: string): string {\n // Determine family from type\n let family = 'general';\n const typeLower = type.toLowerCase();\n for (const [fam, keywords] of Object.entries(TOPIC_KEY_FAMILIES)) {\n if (keywords.some(k => typeLower.includes(k))) {\n family = fam;\n break;\n }\n }\n\n // Normalize title to slug\n const slug = title\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, '') // keep letters, digits, CJK, spaces, hyphens\n .trim()\n .replace(/\\s+/g, '-')\n .slice(0, 60);\n\n if (!slug) return '';\n return `${family}/${slug}`;\n}\n\n/**\n * Reload observations into the Orama index.\n * Called during server startup to restore the search index.\n *\n * Optimization: uses batch embedding (ONNX processes 64 texts at a time)\n * instead of individual embed calls. This reduces startup CPU from minutes\n * to seconds for large observation sets (500+).\n */\nexport async function reindexObservations(): Promise<number> {\n if (observations.length === 0) return 0;\n\n // Reset the Orama index to ensure clean reindex (idempotent)\n await resetDb();\n\n // Batch-generate all embeddings at once (much faster than individual calls)\n let embeddings: (number[] | null)[] = [];\n if (isEmbeddingEnabled()) {\n try {\n const texts = observations.map(obs =>\n [obs.title, obs.narrative, ...obs.facts].join(' '),\n );\n embeddings = await batchGenerateEmbeddings(texts);\n } catch {\n // Batch embedding failed — fall back to no embeddings\n }\n }\n\n let count = 0;\n for (let i = 0; i < observations.length; i++) {\n const obs = observations[i];\n try {\n const embedding = embeddings[i] ?? null;\n const docId = `obs-${obs.id}`;\n const doc: MemorixDocument = {\n id: docId,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.map((c: string) => c.replace(/-/g, ' ')).join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n ...(embedding ? { embedding } : {}),\n };\n await insertObservation(doc);\n count++;\n } catch (err) {\n console.error(`[memorix] Failed to reindex observation #${obs.id}: ${err}`);\n }\n }\n return count;\n}\n","/**\n * Memory Compact Engine\n *\n * Dual-mode memory management inspired by:\n * - Mem0's ADD/UPDATE/DELETE/NONE decision model with content merging\n * - Cipher's dual-mode architecture (LLM + heuristic fallback)\n *\n * Two paths:\n * 1. LLM mode (compactOnWrite): Single LLM call → extract facts + compare + decide + merge\n * 2. Free mode (heuristicCompact): Vector similarity → rule-based ADD/UPDATE/NONE\n *\n * Both paths produce a CompactDecision that the caller executes.\n */\n\nimport { callLLM, isLLMEnabled } from './provider.js';\n\n/** The decision the compact engine makes for each memory operation */\nexport type MemoryAction = 'ADD' | 'UPDATE' | 'DELETE' | 'NONE';\n\n/** Existing memory entry for comparison */\nexport interface ExistingMemory {\n id: number;\n title: string;\n narrative: string;\n facts: string;\n score: number;\n}\n\n/** The compact decision — what to do with the new memory */\nexport interface CompactDecision {\n action: MemoryAction;\n /** ID of existing memory to UPDATE/DELETE */\n targetId?: number;\n /** Brief explanation of why this action was chosen */\n reason: string;\n /** Merged narrative for UPDATE (Mem0-style rewrite) */\n mergedNarrative?: string;\n /** Merged facts for UPDATE */\n mergedFacts?: string[];\n /** LLM-extracted enriched facts (only in LLM mode) */\n enrichedFacts?: string[];\n /** Whether LLM was used for this decision */\n usedLLM: boolean;\n}\n\n/**\n * Unified Compact on Write prompt (Mem0-inspired, single LLM call).\n *\n * This prompt does 3 things in 1 call:\n * 1. Extract structured facts from the new content\n * 2. Compare with existing similar memories\n * 3. Decide ADD/UPDATE/DELETE/NONE and merge if needed\n */\nconst COMPACT_ON_WRITE_PROMPT = `You are a smart coding memory manager. You control the memory of a cross-IDE coding assistant.\n\nYou receive a NEW MEMORY to store and a list of EXISTING similar memories. Your job:\n1. Extract the key facts from the new memory\n2. Compare with existing memories\n3. Decide the best action\n\nActions:\n- ADD: New memory contains unique information. Store it as-is.\n- UPDATE: New memory supersedes or improves an existing one. Merge them into a single, comprehensive memory.\n- DELETE: An existing memory is outdated/contradicted by the new one. Remove it.\n- NONE: New memory is redundant. Existing memories already cover this. Skip storing.\n\nDecision rules:\n- Same topic updated (e.g., \"MySQL → PostgreSQL\"): UPDATE the old memory with merged content\n- Bug fixed that was reported as open: UPDATE the bug report to include the fix\n- Task completed that was tracked as in-progress: UPDATE to mark completed\n- Minor variation of existing memory: NONE (skip)\n- Completely new topic: ADD\n- Old info directly contradicted: DELETE the old one\n- Prefer UPDATE over ADD — keep memory count low, merge information\n\nFor UPDATE: write a merged narrative that combines the best of both old and new, preserving all important details. Also merge the facts lists, removing duplicates.\n\nRespond in JSON only:\n{\n \"action\": \"ADD\" | \"UPDATE\" | \"DELETE\" | \"NONE\",\n \"targetId\": null or existing_memory_id_number,\n \"reason\": \"brief explanation of decision\",\n \"mergedNarrative\": \"merged narrative text (required for UPDATE, null otherwise)\",\n \"mergedFacts\": [\"merged fact 1\", \"merged fact 2\"] or null,\n \"extractedFacts\": [\"fact extracted from new content 1\", \"fact 2\"]\n}`;\n\n// ─── Heuristic Constants (Cipher-inspired) ───────────────────────────\n\n/** Similarity threshold above which we consider memories as \"same topic\" */\nconst SIMILARITY_HIGH = 0.75;\n/** Similarity threshold for \"related but different\" */\nconst SIMILARITY_MEDIUM = 0.5;\n\n// ─── LLM Mode ────────────────────────────────────────────────────────\n\n/**\n * Compact on Write — LLM mode.\n *\n * Single LLM call that extracts facts, compares with existing memories,\n * and decides ADD/UPDATE/DELETE/NONE with merged content.\n *\n * Inspired by Mem0's `get_update_memory_messages` but unified into 1 call.\n */\nexport async function compactOnWrite(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: ExistingMemory[],\n): Promise<CompactDecision> {\n if (!isLLMEnabled()) {\n return heuristicCompact(newMemory, existingMemories);\n }\n\n if (existingMemories.length === 0) {\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\n }\n\n // Build the prompt with new + existing memories (Mem0's temp_uuid_mapping approach)\n const existingList = existingMemories\n .map(m => `[ID: ${m.id}] (similarity: ${m.score.toFixed(2)}) ${m.title}\\n Narrative: ${m.narrative}\\n Facts: ${m.facts}`)\n .join('\\n\\n');\n\n const userMessage = `NEW MEMORY:\nTitle: ${newMemory.title}\nNarrative: ${newMemory.narrative}\nFacts: ${newMemory.facts.join('; ')}\n\nEXISTING SIMILAR MEMORIES:\n${existingList}`;\n\n try {\n const response = await callLLM(COMPACT_ON_WRITE_PROMPT, userMessage);\n\n // Parse response — handle markdown code blocks\n let content = response.content.trim();\n if (content.startsWith('```')) {\n content = content.replace(/^```(?:json)?\\s*/, '').replace(/\\s*```$/, '');\n }\n\n const parsed = JSON.parse(content) as {\n action: string;\n targetId?: number | null;\n reason?: string;\n mergedNarrative?: string | null;\n mergedFacts?: string[] | null;\n extractedFacts?: string[] | null;\n };\n\n // Validate action\n const action = parsed.action?.toUpperCase() as MemoryAction;\n if (!action || !['ADD', 'UPDATE', 'DELETE', 'NONE'].includes(action)) {\n return { action: 'ADD', reason: 'LLM response invalid, defaulting to ADD', usedLLM: true };\n }\n\n // Validate targetId exists in existing memories for UPDATE/DELETE\n if ((action === 'UPDATE' || action === 'DELETE') && parsed.targetId != null) {\n const targetExists = existingMemories.some(m => m.id === parsed.targetId);\n if (!targetExists) {\n // LLM hallucinated an ID (common issue noted in Mem0's code)\n return { action: 'ADD', reason: `LLM referenced non-existent memory #${parsed.targetId}, defaulting to ADD`, usedLLM: true };\n }\n }\n\n return {\n action,\n targetId: parsed.targetId ?? undefined,\n reason: parsed.reason ?? 'LLM decision',\n mergedNarrative: parsed.mergedNarrative ?? undefined,\n mergedFacts: parsed.mergedFacts ?? undefined,\n enrichedFacts: parsed.extractedFacts ?? undefined,\n usedLLM: true,\n };\n } catch (err) {\n // LLM failed — fall back to heuristic\n console.error(`[memorix] LLM compact failed, falling back to heuristic:`, (err as Error)?.message ?? err);\n return heuristicCompact(newMemory, existingMemories);\n }\n}\n\n// ─── Free Mode (Heuristic) ───────────────────────────────────────────\n\n/**\n * Heuristic Compact — Free mode, no LLM needed.\n *\n * Uses vector similarity scores from search results to make decisions.\n * Inspired by Cipher's fallback logic in extract_and_operate_memory.ts.\n *\n * Decision logic:\n * - score >= 0.75: Very similar → check if new is more complete\n * - New is longer/richer → UPDATE (merge)\n * - Otherwise → NONE (skip, already covered)\n * - score >= 0.50: Related topic\n * - Same entity + same type → UPDATE if new has more facts\n * - Otherwise → ADD (different enough)\n * - score < 0.50: Different topic → ADD\n */\nexport function heuristicCompact(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: ExistingMemory[],\n): CompactDecision {\n if (existingMemories.length === 0) {\n return { action: 'ADD', reason: 'No existing memories to compare', usedLLM: false };\n }\n\n const best = existingMemories[0]; // Already sorted by score\n\n // High similarity — very likely same topic\n if (best.score >= SIMILARITY_HIGH) {\n const newLength = newMemory.narrative.length + newMemory.facts.join(' ').length;\n const oldLength = best.narrative.length + best.facts.length;\n\n if (newLength > oldLength * 1.2) {\n // New memory is substantially richer — UPDATE with merged content\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\n return {\n action: 'UPDATE',\n targetId: best.id,\n reason: `New memory is more comprehensive (${newLength} > ${oldLength} chars)`,\n mergedNarrative,\n mergedFacts,\n usedLLM: false,\n };\n }\n\n // New memory is not richer — skip it\n return {\n action: 'NONE',\n targetId: best.id,\n reason: `Existing memory #${best.id} already covers this topic (similarity: ${best.score.toFixed(2)})`,\n usedLLM: false,\n };\n }\n\n // Medium similarity — related but might be different enough\n if (best.score >= SIMILARITY_MEDIUM) {\n const newFactCount = newMemory.facts.length;\n const oldFactCount = best.facts.split('\\n').filter(Boolean).length;\n\n if (newFactCount > oldFactCount) {\n // New has more facts — UPDATE\n const mergedNarrative = mergeTexts(best.narrative, newMemory.narrative);\n const mergedFacts = mergeFacts(best.facts, newMemory.facts.join('\\n'));\n return {\n action: 'UPDATE',\n targetId: best.id,\n reason: `New memory has more facts (${newFactCount} > ${oldFactCount}), merging`,\n mergedNarrative,\n mergedFacts,\n usedLLM: false,\n };\n }\n\n // Related but not richer — ADD as separate memory\n return { action: 'ADD', reason: `Related to #${best.id} but different enough to keep separate`, usedLLM: false };\n }\n\n // Low similarity — new topic\n return { action: 'ADD', reason: 'No similar memories found', usedLLM: false };\n}\n\n// ─── Content Merging Utilities ───────────────────────────────────────\n\n/**\n * Merge two narrative texts, keeping the more comprehensive version\n * while preserving unique information from both.\n */\nfunction mergeTexts(oldText: string, newText: string): string {\n // If new text is significantly longer, prefer it\n if (newText.length > oldText.length * 1.5) return newText;\n // If old text is significantly longer, append new info\n if (oldText.length > newText.length * 1.5) return oldText;\n // Similar length — combine with separator\n return `${newText}\\n\\n[Previous context]: ${oldText}`;\n}\n\n/**\n * Merge two fact lists, removing duplicates.\n * oldFacts is newline-separated string, newFacts is array.\n */\nfunction mergeFacts(oldFactsStr: string, newFactsStr: string): string[] {\n const oldFacts = oldFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\n const newFacts = newFactsStr.split('\\n').filter(Boolean).map(f => f.trim());\n\n const seen = new Set<string>();\n const merged: string[] = [];\n\n // Add new facts first (they're more recent)\n for (const f of newFacts) {\n const normalized = f.toLowerCase();\n if (!seen.has(normalized)) {\n seen.add(normalized);\n merged.push(f);\n }\n }\n\n // Add old facts that aren't duplicates\n for (const f of oldFacts) {\n const normalized = f.toLowerCase();\n if (!seen.has(normalized)) {\n seen.add(normalized);\n merged.push(f);\n }\n }\n\n return merged;\n}\n\n// ─── Batch Dedup (for memorix_deduplicate tool) ──────────────────────\n\n/**\n * LLM-powered dedup for batch cleanup.\n * Compares a new memory against existing ones and returns a decision.\n * Used by memorix_deduplicate tool.\n */\nexport async function deduplicateMemory(\n newMemory: { title: string; narrative: string; facts: string[] },\n existingMemories: Array<{ id: number; title: string; narrative: string; facts: string }>,\n): Promise<CompactDecision | null> {\n if (!isLLMEnabled()) return null;\n if (existingMemories.length === 0) return { action: 'ADD', reason: 'No existing memories', usedLLM: false };\n\n const asExisting: ExistingMemory[] = existingMemories.map(m => ({\n ...m,\n score: 0.8, // Batch dedup assumes high similarity (pre-filtered)\n }));\n\n return compactOnWrite(newMemory, asExisting);\n}\n","/**\n * Session Lifecycle Manager\n *\n * Tracks coding sessions across agents and provides context injection\n * for new sessions. Inspired by Engram's session management pattern.\n *\n * Key features:\n * - Start/end session tracking\n * - Structured session summaries (Goal/Discoveries/Accomplished/Files)\n * - Auto-inject previous session context on session start\n * - Cross-agent session awareness (all agents share session data)\n */\n\nimport type { Session, Observation } from '../types.js';\nimport { loadSessionsJson, saveSessionsJson, loadObservationsJson } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\nimport { resolveAliases } from '../project/aliases.js';\n\n/**\n * Resolve a projectId into a Set of all known aliases.\n * Ensures sessions stored under any alias are found regardless of which IDE stored them.\n */\nasync function resolveProjectIds(projectId: string): Promise<Set<string>> {\n try {\n const aliases = await resolveAliases(projectId);\n return new Set(aliases);\n } catch {\n return new Set([projectId]);\n }\n}\n\n/**\n * Generate a unique session ID.\n */\nfunction generateSessionId(): string {\n const ts = Date.now().toString(36);\n const rand = Math.random().toString(36).slice(2, 8);\n return `sess-${ts}-${rand}`;\n}\n\n/**\n * Start a new coding session.\n *\n * Creates a session record and returns context from previous sessions\n * so the agent can resume work without re-explaining everything.\n */\nexport async function startSession(\n projectDir: string,\n projectId: string,\n opts?: { sessionId?: string; agent?: string },\n): Promise<{ session: Session; previousContext: string }> {\n const sessionId = opts?.sessionId || generateSessionId();\n const now = new Date().toISOString();\n\n const session: Session = {\n id: sessionId,\n projectId,\n startedAt: now,\n status: 'active',\n agent: opts?.agent,\n };\n\n // Load previous context before creating new session\n const previousContext = await getSessionContext(projectDir, projectId);\n\n // Persist with file lock\n await withFileLock(projectDir, async () => {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n\n // Mark any existing active sessions as completed (stale)\n const aliasSet = await resolveProjectIds(projectId);\n for (const s of sessions) {\n if (aliasSet.has(s.projectId) && s.status === 'active') {\n s.status = 'completed';\n s.endedAt = now;\n if (!s.summary) {\n s.summary = '(session ended implicitly by new session start)';\n }\n }\n }\n\n sessions.push(session);\n await saveSessionsJson(projectDir, sessions);\n });\n\n return { session, previousContext };\n}\n\n/**\n * End a coding session with an optional structured summary.\n *\n * Summary format (following Engram's convention):\n * ## Goal\n * ## Discoveries\n * ## Accomplished\n * ## Relevant Files\n */\nexport async function endSession(\n projectDir: string,\n sessionId: string,\n summary?: string,\n): Promise<Session | null> {\n let endedSession: Session | null = null;\n\n await withFileLock(projectDir, async () => {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n const session = sessions.find(s => s.id === sessionId);\n\n if (!session) return;\n\n session.status = 'completed';\n session.endedAt = new Date().toISOString();\n if (summary) {\n session.summary = summary;\n }\n\n endedSession = session;\n await saveSessionsJson(projectDir, sessions);\n });\n\n return endedSession;\n}\n\n/**\n * Get formatted context from previous sessions for injection into a new session.\n *\n * Returns a concise summary of:\n * 1. Last completed session's summary (if available)\n * 2. Top observations from recent sessions\n * 3. Active decisions and gotchas\n */\nexport async function getSessionContext(\n projectDir: string,\n projectId: string,\n limit: number = 3,\n): Promise<string> {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n const allObs = await loadObservationsJson(projectDir) as Observation[];\n\n // Get recent completed sessions for this project (newest first)\n const aliasSet = await resolveProjectIds(projectId);\n const projectSessions = sessions\n .filter(s => aliasSet.has(s.projectId) && s.status === 'completed')\n .sort((a, b) => new Date(b.endedAt || b.startedAt).getTime() - new Date(a.endedAt || a.startedAt).getTime())\n .slice(0, limit);\n\n if (projectSessions.length === 0 && allObs.length === 0) {\n return '';\n }\n\n const lines: string[] = [];\n\n // Last session summary\n if (projectSessions.length > 0) {\n const last = projectSessions[0];\n lines.push(`## Previous Session`);\n if (last.agent) {\n lines.push(`Agent: ${last.agent}`);\n }\n lines.push(`Ended: ${last.endedAt || last.startedAt}`);\n if (last.summary && last.summary !== '(session ended implicitly by new session start)') {\n lines.push('');\n lines.push(last.summary);\n }\n lines.push('');\n }\n\n // High-priority recent observations (gotchas, decisions, discoveries)\n const PRIORITY_TYPES = new Set(['gotcha', 'decision', 'problem-solution', 'trade-off', 'discovery']);\n const TYPE_EMOJI: Record<string, string> = {\n 'gotcha': '🔴', 'decision': '🟤', 'problem-solution': '🟡',\n 'trade-off': '⚖️', 'discovery': '🟣', 'how-it-works': '🔵',\n 'what-changed': '🟢', 'why-it-exists': '🟠', 'session-request': '🎯',\n };\n\n const priorityObs = allObs\n .filter(o => aliasSet.has(o.projectId) && PRIORITY_TYPES.has(o.type))\n .sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime())\n .slice(0, 5);\n\n if (priorityObs.length > 0) {\n lines.push(`## Key Memories`);\n for (const obs of priorityObs) {\n const emoji = TYPE_EMOJI[obs.type] ?? '📌';\n const fact = obs.facts?.[0] ? ` — ${obs.facts[0]}` : '';\n lines.push(`${emoji} ${obs.title}${fact}`);\n }\n lines.push('');\n }\n\n // Session history summary\n if (projectSessions.length > 1) {\n lines.push(`## Session History (last ${projectSessions.length})`);\n for (const s of projectSessions) {\n const date = (s.endedAt || s.startedAt).slice(0, 10);\n const agent = s.agent ? ` [${s.agent}]` : '';\n const summary = s.summary\n ? ` — ${s.summary.split('\\n')[0].replace(/^#+\\s*/, '').slice(0, 80)}`\n : '';\n lines.push(`- ${date}${agent}${summary}`);\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n/**\n * List all sessions for a project.\n */\nexport async function listSessions(\n projectDir: string,\n projectId?: string,\n): Promise<Session[]> {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n if (projectId) {\n const aliasSet = await resolveProjectIds(projectId);\n return sessions.filter(s => aliasSet.has(s.projectId));\n }\n return sessions;\n}\n\n/**\n * Get the currently active session for a project (if any).\n */\nexport async function getActiveSession(\n projectDir: string,\n projectId: string,\n): Promise<Session | null> {\n const sessions = await loadSessionsJson(projectDir) as Session[];\n const aliasSet = await resolveProjectIds(projectId);\n return sessions.find(s => aliasSet.has(s.projectId) && s.status === 'active') || null;\n}\n","/**\n * Retention & Decay Engine\n *\n * Manages memory relevance over time using exponential decay.\n * Sources:\n * - mcp-memory-service: ExponentialDecayCalculator (importance × decay × access_boost)\n * - MemCP: Active → Archive → Purge lifecycle with immunity rules\n *\n * Relevance formula:\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost × connectionBoost\n *\n * Immunity: observations with importance=critical, accessCount>=3, or tagged \"keep\"/\"pinned\"\n * are never auto-archived.\n */\n\nimport type { MemorixDocument, Observation } from '../types.js';\nimport { loadObservationsJson, saveObservationsJson, appendArchivedObservations } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\n// ── Importance → Retention Period mapping ────────────────────────────\n\nexport type ImportanceLevel = 'critical' | 'high' | 'medium' | 'low';\n\nconst RETENTION_DAYS: Record<ImportanceLevel, number> = {\n critical: 365,\n high: 180,\n medium: 90,\n low: 30,\n};\n\nconst BASE_IMPORTANCE: Record<ImportanceLevel, number> = {\n critical: 1.0,\n high: 0.8,\n medium: 0.5,\n low: 0.3,\n};\n\n// ── Observation Type → Default Importance ────────────────────────────\n\nconst TYPE_IMPORTANCE: Record<string, ImportanceLevel> = {\n gotcha: 'high',\n decision: 'high',\n 'trade-off': 'high',\n 'problem-solution': 'medium',\n 'how-it-works': 'medium',\n 'what-changed': 'low',\n 'why-it-exists': 'medium',\n discovery: 'low',\n 'session-request': 'low',\n};\n\n// ── Immunity ─────────────────────────────────────────────────────────\n\nconst PROTECTED_TAGS = new Set(['keep', 'important', 'pinned', 'critical']);\nconst MIN_ACCESS_FOR_IMMUNITY = 3;\n\n/**\n * Check if an observation is immune from archiving/decay.\n * Immune observations maintain a minimum relevance score.\n */\nexport function isImmune(doc: MemorixDocument): boolean {\n const importance = getImportanceLevel(doc);\n if (importance === 'critical' || importance === 'high') return true;\n if ((doc.accessCount ?? 0) >= MIN_ACCESS_FOR_IMMUNITY) return true;\n\n const concepts = doc.concepts?.split(', ').map((c) => c.toLowerCase()) ?? [];\n return concepts.some((c) => PROTECTED_TAGS.has(c));\n}\n\n// ── Relevance Scoring ────────────────────────────────────────────────\n\nexport interface RelevanceScore {\n observationId: number;\n totalScore: number;\n baseImportance: number;\n decayFactor: number;\n accessBoost: number;\n ageDays: number;\n isImmune: boolean;\n}\n\n/**\n * Get the importance level for an observation based on its type.\n */\nexport function getImportanceLevel(doc: MemorixDocument): ImportanceLevel {\n return TYPE_IMPORTANCE[doc.type] ?? 'medium';\n}\n\n/**\n * Calculate the relevance score for a single observation.\n *\n * Formula (from mcp-memory-service):\n * score = baseImportance × e^(-ageDays / retentionPeriod) × accessBoost\n *\n * Access boost (from mcp-memory-service):\n * 1 + 0.1 × accessCount (10% boost per access, capped at 2.0)\n */\nexport function calculateRelevance(\n doc: MemorixDocument,\n referenceTime?: Date,\n): RelevanceScore {\n const now = referenceTime ?? new Date();\n const importance = getImportanceLevel(doc);\n const base = BASE_IMPORTANCE[importance];\n const retention = RETENTION_DAYS[importance];\n\n // Age in days\n const createdAt = new Date(doc.createdAt);\n const ageDays = Math.max(0, (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24));\n\n // Exponential decay\n const decayFactor = Math.exp(-ageDays / retention);\n\n // Access boost: 10% per access, capped at 2.0×\n const accessCount = doc.accessCount ?? 0;\n const accessBoost = Math.min(2.0, 1 + 0.1 * accessCount);\n\n let totalScore = base * decayFactor * accessBoost;\n\n // Immune observations get minimum 0.5 relevance\n const immune = isImmune(doc);\n if (immune) {\n totalScore = Math.max(totalScore, 0.5);\n }\n\n return {\n observationId: doc.observationId,\n totalScore,\n baseImportance: base,\n decayFactor,\n accessBoost,\n ageDays,\n isImmune: immune,\n };\n}\n\n/**\n * Score and rank observations by relevance.\n * Returns sorted (highest relevance first) with scores.\n */\nexport function rankByRelevance(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): RelevanceScore[] {\n return docs\n .map((doc) => calculateRelevance(doc, referenceTime))\n .sort((a, b) => b.totalScore - a.totalScore);\n}\n\n// ── Retention Lifecycle ──────────────────────────────────────────────\n\nexport type RetentionZone = 'active' | 'stale' | 'archive-candidate';\n\n/**\n * Classify an observation into a retention zone.\n *\n * Lifecycle (from MemCP):\n * Active: recently accessed or high importance\n * Stale: not accessed, beyond 50% of retention period\n * Archive-candidate: not accessed, beyond 100% of retention period, not immune\n */\nexport function getRetentionZone(doc: MemorixDocument, referenceTime?: Date): RetentionZone {\n const now = referenceTime ?? new Date();\n const importance = getImportanceLevel(doc);\n const retention = RETENTION_DAYS[importance];\n\n const createdAt = new Date(doc.createdAt);\n const ageDays = (now.getTime() - createdAt.getTime()) / (1000 * 60 * 60 * 24);\n\n // Recently accessed = active regardless of age\n if (doc.lastAccessedAt) {\n const lastAccess = new Date(doc.lastAccessedAt);\n const daysSinceAccess = (now.getTime() - lastAccess.getTime()) / (1000 * 60 * 60 * 24);\n if (daysSinceAccess < 7) return 'active';\n }\n\n if (isImmune(doc)) return 'active';\n if (ageDays > retention) return 'archive-candidate';\n if (ageDays > retention * 0.5) return 'stale';\n return 'active';\n}\n\n/**\n * Get archive candidates from a list of observations.\n * Returns observations that are beyond their retention period and not immune.\n */\nexport function getArchiveCandidates(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): MemorixDocument[] {\n return docs.filter((doc) => getRetentionZone(doc, referenceTime) === 'archive-candidate');\n}\n\n/**\n * Get retention summary statistics.\n */\nexport function getRetentionSummary(\n docs: MemorixDocument[],\n referenceTime?: Date,\n): { active: number; stale: number; archiveCandidates: number; immune: number } {\n let active = 0;\n let stale = 0;\n let archiveCandidates = 0;\n let immune = 0;\n\n for (const doc of docs) {\n const zone = getRetentionZone(doc, referenceTime);\n if (zone === 'active') active++;\n else if (zone === 'stale') stale++;\n else archiveCandidates++;\n if (isImmune(doc)) immune++;\n }\n\n return { active, stale, archiveCandidates, immune };\n}\n\n// ── Auto-Archive ────────────────────────────────────────────────────\n\n/**\n * Archive expired observations: move archive-candidates from active\n * storage to observations.archived.json.\n *\n * Returns the count of archived observations.\n * Uses file locking for cross-process safety.\n */\nexport async function archiveExpired(\n projectDir: string,\n referenceTime?: Date,\n accessMap?: Map<number, { accessCount: number; lastAccessedAt: string }>,\n): Promise<{ archived: number; remaining: number }> {\n return await withFileLock(projectDir, async () => {\n const allObs = await loadObservationsJson(projectDir) as Observation[];\n\n // Convert to MemorixDocument-like shape for zone calculation\n // Use accessMap (from Orama index) when available for accurate immunity checks\n const toDoc = (obs: Observation): MemorixDocument => {\n const access = accessMap?.get(obs.id);\n return {\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: access?.accessCount ?? 0,\n lastAccessedAt: access?.lastAccessedAt ?? '',\n status: obs.status ?? 'active',\n };\n };\n\n const toArchive: Observation[] = [];\n const toKeep: Observation[] = [];\n\n for (const obs of allObs) {\n const doc = toDoc(obs);\n const zone = getRetentionZone(doc, referenceTime);\n if (zone === 'archive-candidate') {\n toArchive.push(obs);\n } else {\n toKeep.push(obs);\n }\n }\n\n if (toArchive.length === 0) {\n return { archived: 0, remaining: allObs.length };\n }\n\n // Move to archive file, then update active file\n await appendArchivedObservations(projectDir, toArchive);\n await saveObservationsJson(projectDir, toKeep);\n\n return { archived: toArchive.length, remaining: toKeep.length };\n });\n}\n","/**\r\n * Skills Engine — Memory-Driven Project Skills\r\n *\r\n * Memorix's unique take on agent skills:\r\n * - Discovers existing SKILL.md files across all 7 agents\r\n * - Auto-generates project-specific skills from observation patterns\r\n * - Injects skill content directly into agent context (no file reading needed)\r\n *\r\n * Unlike generic skill marketplaces, these skills are derived from YOUR\r\n * project's actual history—decisions, gotchas, patterns, and solutions\r\n * that make this project unique.\r\n *\r\n * SKILL.md format (industry standard):\r\n * ---\r\n * description: Short description for tool use\r\n * ---\r\n * # Skill Title\r\n * Markdown instructions...\r\n */\r\n\r\nimport { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from 'node:fs';\r\nimport { join } from 'node:path';\r\nimport { homedir } from 'node:os';\r\nimport type { AgentTarget, SkillEntry } from '../types.js';\r\n\r\n// ============================================================\r\n// Types\r\n// ============================================================\r\n\r\n/** A skill with full content (for inject/generate) */\r\nexport interface SkillFull extends SkillEntry {\r\n content: string;\r\n /** Whether this was auto-generated from observations */\r\n generated: boolean;\r\n}\r\n\r\n/** Observation data for skill generation */\r\ninterface ObsData {\r\n id: number;\r\n entityName: string;\r\n type: string;\r\n title: string;\r\n narrative: string;\r\n facts?: string[];\r\n concepts?: string[];\r\n filesModified?: string[];\r\n createdAt?: string;\r\n}\r\n\r\n/** Entity cluster for skill generation */\r\ninterface EntityCluster {\r\n entity: string;\r\n observations: ObsData[];\r\n /** Types present in cluster */\r\n types: Set<string>;\r\n /** Score: higher = more skill-worthy */\r\n score: number;\r\n}\r\n\r\n// ============================================================\r\n// Skills Engine\r\n// ============================================================\r\n\r\n/** Skills directories per agent (same as workspace engine) */\r\nconst SKILLS_DIRS: Record<AgentTarget, string[]> = {\r\n codex: ['.codex/skills', '.agents/skills'],\r\n cursor: ['.cursor/skills', '.cursor/skills-cursor'],\r\n windsurf: ['.windsurf/skills'],\r\n 'claude-code': ['.claude/skills'],\r\n copilot: ['.github/skills', '.copilot/skills'],\r\n antigravity: ['.agent/skills', '.gemini/skills', '.gemini/antigravity/skills'],\r\n kiro: ['.kiro/skills'],\r\n opencode: ['.opencode/skills'],\r\n trae: ['.trae/skills'],\r\n};\r\n\r\n/** Types with high signal for skill generation */\r\nconst SKILL_WORTHY_TYPES = new Set([\r\n 'gotcha', 'decision', 'how-it-works', 'problem-solution', 'trade-off',\r\n]);\r\n\r\n/** Minimum observations needed per entity to generate a skill */\r\nconst MIN_OBS_FOR_SKILL = 3;\r\n\r\n/** Minimum score for skill generation */\r\nconst MIN_SCORE_FOR_SKILL = 5;\r\n\r\nexport class SkillsEngine {\r\n private skipGlobal: boolean;\r\n constructor(private projectRoot: string, options?: { skipGlobal?: boolean }) {\r\n this.skipGlobal = options?.skipGlobal ?? false;\r\n }\r\n\r\n // ============================================================\r\n // List: Discover all available skills\r\n // ============================================================\r\n\r\n /**\r\n * List all available skills from all agents + generated suggestions.\r\n */\r\n listSkills(): SkillFull[] {\r\n const skills: SkillFull[] = [];\r\n const seen = new Set<string>();\r\n const home = homedir();\r\n\r\n for (const [agent, dirs] of Object.entries(SKILLS_DIRS)) {\r\n for (const dir of dirs) {\r\n const paths = [join(this.projectRoot, dir)];\r\n if (!this.skipGlobal) {\r\n paths.push(join(home, dir));\r\n }\r\n\r\n for (const skillsRoot of paths) {\r\n if (!existsSync(skillsRoot)) continue;\r\n\r\n try {\r\n const entries = readdirSync(skillsRoot, { withFileTypes: true });\r\n for (const entry of entries) {\r\n if (!entry.isDirectory()) continue;\r\n const name = entry.name;\r\n if (seen.has(name)) continue;\r\n\r\n const skillMd = join(skillsRoot, name, 'SKILL.md');\r\n if (!existsSync(skillMd)) continue;\r\n\r\n try {\r\n const content = readFileSync(skillMd, 'utf-8');\r\n const description = this.parseDescription(content);\r\n\r\n skills.push({\r\n name,\r\n description,\r\n sourcePath: join(skillsRoot, name),\r\n sourceAgent: agent as AgentTarget,\r\n content,\r\n generated: false,\r\n });\r\n seen.add(name);\r\n } catch { /* skip unreadable */ }\r\n }\r\n } catch { /* skip unreadable dirs */ }\r\n }\r\n }\r\n }\r\n\r\n return skills;\r\n }\r\n\r\n // ============================================================\r\n // Generate: Create skills from observation patterns\r\n // ============================================================\r\n\r\n /**\r\n * Analyze observations and generate SKILL.md content for entities with\r\n * rich knowledge accumulation.\r\n */\r\n generateFromObservations(observations: ObsData[]): SkillFull[] {\r\n // 1. Cluster observations by entity\r\n const clusters = this.clusterByEntity(observations);\r\n\r\n // 2. Score each cluster for skill-worthiness\r\n for (const cluster of clusters.values()) {\r\n cluster.score = this.scoreCluster(cluster);\r\n }\r\n\r\n // 3. Generate skills for top clusters\r\n const results: SkillFull[] = [];\r\n const sortedClusters = [...clusters.values()]\r\n .filter(c => c.score >= MIN_SCORE_FOR_SKILL)\r\n .sort((a, b) => b.score - a.score)\r\n .slice(0, 10); // Max 10 auto-generated skills\r\n\r\n for (const cluster of sortedClusters) {\r\n const skill = this.clusterToSkill(cluster);\r\n if (skill) results.push(skill);\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Write a generated skill to the target agent's skills directory.\r\n */\r\n writeSkill(skill: SkillFull, target: AgentTarget): string | null {\r\n const dirs = SKILLS_DIRS[target];\r\n if (!dirs || dirs.length === 0) return null;\r\n\r\n const targetDir = join(this.projectRoot, dirs[0], skill.name);\r\n\r\n try {\r\n mkdirSync(targetDir, { recursive: true });\r\n writeFileSync(join(targetDir, 'SKILL.md'), skill.content, 'utf-8');\r\n return join(dirs[0], skill.name, 'SKILL.md');\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n // ============================================================\r\n // Inject: Return skill content for direct agent consumption\r\n // ============================================================\r\n\r\n /**\r\n * Get full content of a skill by name (for direct injection).\r\n */\r\n injectSkill(name: string): SkillFull | null {\r\n const all = this.listSkills();\r\n return all.find(s => s.name.toLowerCase() === name.toLowerCase()) || null;\r\n }\r\n\r\n // ============================================================\r\n // Internal helpers\r\n // ============================================================\r\n\r\n private parseDescription(content: string): string {\r\n const match = content.match(/^---[\\s\\S]*?description:\\s*[\"']?(.+?)[\"']?\\s*$/m);\r\n return match ? match[1] : '';\r\n }\r\n\r\n private clusterByEntity(observations: ObsData[]): Map<string, EntityCluster> {\r\n const clusters = new Map<string, EntityCluster>();\r\n\r\n for (const obs of observations) {\r\n const entity = obs.entityName || 'unknown';\r\n let cluster = clusters.get(entity);\r\n if (!cluster) {\r\n cluster = { entity, observations: [], types: new Set(), score: 0 };\r\n clusters.set(entity, cluster);\r\n }\r\n cluster.observations.push(obs);\r\n cluster.types.add(obs.type);\r\n }\r\n\r\n return clusters;\r\n }\r\n\r\n private scoreCluster(cluster: EntityCluster): number {\r\n let score = 0;\r\n const obs = cluster.observations;\r\n\r\n // Base: need minimum observations\r\n if (obs.length < MIN_OBS_FOR_SKILL) return 0;\r\n\r\n // Must have at least one skill-worthy type (gotcha/decision/how-it-works/etc.)\r\n let hasSkillWorthyType = false;\r\n for (const type of cluster.types) {\r\n if (SKILL_WORTHY_TYPES.has(type)) {\r\n hasSkillWorthyType = true;\r\n break;\r\n }\r\n }\r\n if (!hasSkillWorthyType) return 0;\r\n\r\n // Volume bonus (1 point per obs, capped at 5)\r\n score += Math.min(obs.length, 5);\r\n\r\n // Type diversity bonus (3 points per unique skill-worthy type)\r\n for (const type of cluster.types) {\r\n if (SKILL_WORTHY_TYPES.has(type)) score += 3;\r\n }\r\n\r\n // Gotcha bonus (critical knowledge that MUST be preserved)\r\n const gotchas = obs.filter(o => o.type === 'gotcha').length;\r\n score += gotchas * 3;\r\n\r\n // Decision bonus (architecture choices that define patterns)\r\n const decisions = obs.filter(o => o.type === 'decision').length;\r\n score += decisions * 2;\r\n\r\n // Facts bonus (structured knowledge)\r\n const totalFacts = obs.reduce((sum, o) => sum + (o.facts?.length || 0), 0);\r\n score += Math.min(totalFacts, 5);\r\n\r\n // Files bonus (indicates real code involvement)\r\n const totalFiles = new Set(obs.flatMap(o => o.filesModified || [])).size;\r\n score += Math.min(totalFiles, 5);\r\n\r\n return score;\r\n }\r\n\r\n private clusterToSkill(cluster: EntityCluster): SkillFull | null {\r\n const { entity, observations } = cluster;\r\n const safeName = entity.replace(/[^a-zA-Z0-9_-]/g, '-').toLowerCase();\r\n\r\n // Group observations by type\r\n const gotchas = observations.filter(o => o.type === 'gotcha');\r\n const decisions = observations.filter(o => o.type === 'decision');\r\n const howItWorks = observations.filter(o => o.type === 'how-it-works');\r\n const problems = observations.filter(o => o.type === 'problem-solution');\r\n const tradeoffs = observations.filter(o => o.type === 'trade-off');\r\n const others = observations.filter(o =>\r\n !['gotcha', 'decision', 'how-it-works', 'problem-solution', 'trade-off'].includes(o.type),\r\n );\r\n\r\n // Collect all facts and concepts\r\n const allFacts = [...new Set(observations.flatMap(o => o.facts || []))];\r\n const allConcepts = [...new Set(observations.flatMap(o => o.concepts || []))];\r\n const allFiles = [...new Set(observations.flatMap(o => o.filesModified || []))];\r\n\r\n // Build SKILL.md content\r\n const lines: string[] = [];\r\n\r\n // Frontmatter\r\n const description = this.generateDescription(cluster);\r\n lines.push('---');\r\n lines.push(`description: ${description}`);\r\n lines.push('---');\r\n lines.push('');\r\n\r\n // Title\r\n lines.push(`# ${entity}`);\r\n lines.push('');\r\n lines.push(`> Auto-generated from ${observations.length} project observations by Memorix.`);\r\n lines.push('> Adapt to your actual project context before relying on this skill.');\r\n lines.push('');\r\n\r\n // Key files\r\n if (allFiles.length > 0) {\r\n lines.push('## Key Files');\r\n lines.push('');\r\n for (const f of allFiles.slice(0, 15)) {\r\n lines.push(`- \\`${f}\\``);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // Critical gotchas (most important — put first)\r\n if (gotchas.length > 0) {\r\n lines.push('## ⚠️ Critical Gotchas');\r\n lines.push('');\r\n for (const g of gotchas) {\r\n lines.push(`### ${g.title}`);\r\n if (g.narrative) lines.push('', g.narrative);\r\n if (g.facts && g.facts.length > 0) {\r\n lines.push('', ...g.facts.map(f => `- ${f}`));\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Architecture decisions\r\n if (decisions.length > 0) {\r\n lines.push('## 🏗️ Architecture Decisions');\r\n lines.push('');\r\n for (const d of decisions) {\r\n lines.push(`### ${d.title}`);\r\n if (d.narrative) lines.push('', d.narrative);\r\n if (d.facts && d.facts.length > 0) {\r\n lines.push('', ...d.facts.map(f => `- ${f}`));\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // How it works\r\n if (howItWorks.length > 0) {\r\n lines.push('## 📖 How It Works');\r\n lines.push('');\r\n for (const h of howItWorks) {\r\n lines.push(`### ${h.title}`);\r\n if (h.narrative) lines.push('', h.narrative);\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Common problems & solutions\r\n if (problems.length > 0) {\r\n lines.push('## 🔧 Common Problems & Solutions');\r\n lines.push('');\r\n for (const p of problems) {\r\n lines.push(`### ${p.title}`);\r\n if (p.narrative) lines.push('', p.narrative);\r\n if (p.facts && p.facts.length > 0) {\r\n lines.push('', ...p.facts.map(f => `- ${f}`));\r\n }\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Trade-offs\r\n if (tradeoffs.length > 0) {\r\n lines.push('## ⚖️ Trade-offs');\r\n lines.push('');\r\n for (const t of tradeoffs) {\r\n lines.push(`### ${t.title}`);\r\n if (t.narrative) lines.push('', t.narrative);\r\n lines.push('');\r\n }\r\n }\r\n\r\n // Other notable observations\r\n if (others.length > 0) {\r\n lines.push('## 📝 Notes');\r\n lines.push('');\r\n for (const o of others.slice(0, 5)) {\r\n lines.push(`- **${o.title}**: ${o.narrative?.split('\\n')[0] || ''}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n // Key concepts\r\n if (allConcepts.length > 0) {\r\n lines.push('## 🏷️ Related Concepts');\r\n lines.push('');\r\n lines.push(allConcepts.map(c => `\\`${c}\\``).join(', '));\r\n lines.push('');\r\n }\r\n\r\n // Quick facts summary\r\n if (allFacts.length > 0) {\r\n lines.push('## 📌 Quick Facts');\r\n lines.push('');\r\n for (const f of allFacts.slice(0, 15)) {\r\n lines.push(`- ${f}`);\r\n }\r\n lines.push('');\r\n }\r\n\r\n const content = lines.join('\\n');\r\n\r\n return {\r\n name: safeName,\r\n description,\r\n sourcePath: '',\r\n sourceAgent: 'codex' as AgentTarget, // generated skills follow SKILL.md standard\r\n content,\r\n generated: true,\r\n };\r\n }\r\n\r\n private generateDescription(cluster: EntityCluster): string {\r\n const parts: string[] = [];\r\n const typeCounts: Record<string, number> = {};\r\n for (const obs of cluster.observations) {\r\n typeCounts[obs.type] = (typeCounts[obs.type] || 0) + 1;\r\n }\r\n\r\n if (typeCounts['gotcha']) parts.push(`${typeCounts['gotcha']} gotcha(s)`);\r\n if (typeCounts['decision']) parts.push(`${typeCounts['decision']} decision(s)`);\r\n if (typeCounts['how-it-works']) parts.push(`${typeCounts['how-it-works']} explanation(s)`);\r\n if (typeCounts['problem-solution']) parts.push(`${typeCounts['problem-solution']} fix(es)`);\r\n\r\n const summary = parts.length > 0 ? parts.join(', ') : `${cluster.observations.length} observations`;\r\n return `Project patterns for ${cluster.entity}: ${summary}`;\r\n }\r\n}\r\n","/**\n * Mini-Skills Engine — Promoted memories that never decay\n *\n * Converts important observations into permanent, actionable \"mini-skills\"\n * that are automatically injected into agent context during session_start.\n *\n * Unlike generic SKILL.md files from marketplaces, mini-skills are:\n * - Derived from YOUR project's actual memories (gotchas, decisions, fixes)\n * - Immune from retention decay (permanent knowledge)\n * - Auto-injected at session start (agents proactively apply them)\n * - Cross-IDE shared (stored in ~/.memorix/data/ alongside observations)\n *\n * Lifecycle: observation → memorix_promote → mini-skill → session_start injection\n */\n\nimport type { MiniSkill, Observation } from '../types.js';\nimport {\n loadMiniSkillsJson,\n saveMiniSkillsJson,\n loadMiniSkillsCounter,\n saveMiniSkillsCounter,\n} from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\n// ── Promote observations to mini-skills ──────────────────────────\n\nexport interface PromoteOptions {\n /** Override auto-generated trigger description */\n trigger?: string;\n /** Override auto-generated instruction */\n instruction?: string;\n /** Extra tags */\n tags?: string[];\n}\n\n/**\n * Promote one or more observations into a mini-skill.\n * The source observations are NOT deleted — they remain in the observation store\n * but the mini-skill is the permanent, never-decaying version.\n */\nexport async function promoteToMiniSkill(\n projectDir: string,\n projectId: string,\n observations: Observation[],\n options?: PromoteOptions,\n): Promise<MiniSkill> {\n return await withFileLock(projectDir, async () => {\n const existing = (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n let nextId = await loadMiniSkillsCounter(projectDir);\n\n // Auto-generate content from observations\n const title = generateTitle(observations);\n const instruction = options?.instruction || generateInstruction(observations);\n const trigger = options?.trigger || generateTrigger(observations);\n const facts = extractFacts(observations);\n const tags = [\n ...(options?.tags || []),\n ...extractTags(observations),\n ];\n\n const skill: MiniSkill = {\n id: nextId,\n sourceObservationIds: observations.map(o => o.id),\n sourceEntity: observations[0]?.entityName || 'unknown',\n title,\n instruction,\n trigger,\n facts,\n projectId,\n createdAt: new Date().toISOString(),\n usedCount: 0,\n tags: [...new Set(tags)],\n };\n\n existing.push(skill);\n nextId++;\n\n await saveMiniSkillsJson(projectDir, existing);\n await saveMiniSkillsCounter(projectDir, nextId);\n\n return skill;\n });\n}\n\n// ── Load & query mini-skills ─────────────────────────────────────\n\n/**\n * Load all mini-skills for a project.\n */\nexport async function loadMiniSkills(\n projectDir: string,\n projectId?: string,\n): Promise<MiniSkill[]> {\n const all = (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n if (!projectId) return all;\n return all.filter(s => s.projectId === projectId);\n}\n\n/**\n * Load all mini-skills (unfiltered).\n */\nexport async function loadAllMiniSkills(projectDir: string): Promise<MiniSkill[]> {\n return (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n}\n\n/**\n * Delete a mini-skill by ID.\n */\nexport async function deleteMiniSkill(\n projectDir: string,\n skillId: number,\n): Promise<boolean> {\n return await withFileLock(projectDir, async () => {\n const existing = (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n const idx = existing.findIndex(s => s.id === skillId);\n if (idx === -1) return false;\n existing.splice(idx, 1);\n await saveMiniSkillsJson(projectDir, existing);\n return true;\n });\n}\n\n/**\n * Increment usedCount for skills that were injected in session_start.\n */\nexport async function recordMiniSkillUsage(\n projectDir: string,\n skillIds: number[],\n): Promise<void> {\n if (skillIds.length === 0) return;\n await withFileLock(projectDir, async () => {\n const existing = (await loadMiniSkillsJson(projectDir)) as MiniSkill[];\n for (const skill of existing) {\n if (skillIds.includes(skill.id)) {\n skill.usedCount++;\n }\n }\n await saveMiniSkillsJson(projectDir, existing);\n });\n}\n\n// ── Format mini-skills for session injection ─────────────────────\n\n/**\n * Format mini-skills for injection into session_start context.\n * Returns a markdown string ready to append to session context.\n */\nexport function formatMiniSkillsForInjection(skills: MiniSkill[]): string {\n if (skills.length === 0) return '';\n\n const lines = [\n `## 🎯 Project Mini-Skills (${skills.length} active)`,\n '',\n ];\n\n for (const skill of skills) {\n lines.push(`### ${skill.title}`);\n lines.push(`**Do**: ${skill.instruction}`);\n lines.push(`**When**: ${skill.trigger}`);\n if (skill.facts.length > 0) {\n for (const fact of skill.facts) {\n lines.push(`- ${fact}`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n\n// ── Auto-generation helpers ──────────────────────────────────────\n\nfunction generateTitle(observations: Observation[]): string {\n if (observations.length === 1) {\n return observations[0].title;\n }\n // Multiple observations — use the first one's title as base\n return observations[0].title;\n}\n\nfunction generateInstruction(observations: Observation[]): string {\n // Convert narrative into imperative instruction\n const obs = observations[0];\n const narrative = obs.narrative || '';\n\n // For gotchas, flip to \"avoid\" instruction\n if (obs.type === 'gotcha') {\n return `Avoid: ${narrative.split('\\n')[0]}`;\n }\n // For decisions, state the chosen approach\n if (obs.type === 'decision') {\n return `Follow: ${narrative.split('\\n')[0]}`;\n }\n // For problem-solution, state the solution\n if (obs.type === 'problem-solution') {\n return `Apply fix: ${narrative.split('\\n')[0]}`;\n }\n // Default: use narrative as-is\n return narrative.split('\\n')[0] || obs.title;\n}\n\nfunction generateTrigger(observations: Observation[]): string {\n const obs = observations[0];\n\n // Use entity name + file paths as trigger context\n const parts: string[] = [];\n if (obs.entityName && obs.entityName !== 'unknown') {\n parts.push(`Working on ${obs.entityName}`);\n }\n if (obs.filesModified.length > 0) {\n parts.push(`touching ${obs.filesModified.slice(0, 3).join(', ')}`);\n }\n if (obs.concepts.length > 0) {\n parts.push(`involving ${obs.concepts.slice(0, 3).join(', ')}`);\n }\n\n return parts.length > 0 ? parts.join('; ') : `Related to ${obs.title}`;\n}\n\nfunction extractFacts(observations: Observation[]): string[] {\n const facts = new Set<string>();\n for (const obs of observations) {\n for (const f of obs.facts) {\n facts.add(f);\n }\n }\n return [...facts].slice(0, 10);\n}\n\nfunction extractTags(observations: Observation[]): string[] {\n const tags = new Set<string>();\n for (const obs of observations) {\n tags.add(obs.type);\n for (const c of obs.concepts) {\n if (c.length <= 30) tags.add(c.toLowerCase());\n }\n }\n return [...tags].slice(0, 10);\n}\n","/**\n * Memory Consolidation Engine\n *\n * Merges similar observations into consolidated summaries to prevent data bloat.\n * Uses text similarity (Jaccard on token n-grams) to find clusters of related\n * observations, then merges them into a single observation preserving key facts.\n *\n * Strategy:\n * 1. Group observations by entity + type\n * 2. Within each group, compute pairwise similarity\n * 3. Cluster observations above a similarity threshold\n * 4. Merge each cluster into a consolidated observation\n * 5. Remove originals, keep the merged result\n *\n * Inspired by Engram's duplicate_count and MemCP's MAGMA consolidation.\n */\n\nimport type { Observation } from '../types.js';\nimport { loadObservationsJson, saveObservationsJson } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\n/** Default similarity threshold for merging (0.0-1.0) */\nconst DEFAULT_SIMILARITY_THRESHOLD = 0.45;\n\n/** Minimum cluster size to trigger consolidation */\nconst MIN_CLUSTER_SIZE = 2;\n\n/** Maximum observations to process in one consolidation run */\nconst MAX_BATCH_SIZE = 500;\n\n/**\n * Tokenize text into word-level tokens for similarity comparison.\n */\nfunction tokenize(text: string): Set<string> {\n return new Set(\n text\n .toLowerCase()\n .replace(/[^a-z0-9\\u4e00-\\u9fff\\s-]/g, ' ')\n .split(/\\s+/)\n .filter(t => t.length > 1),\n );\n}\n\n/**\n * Compute Jaccard similarity between two sets of tokens.\n */\nfunction jaccardSimilarity(a: Set<string>, b: Set<string>): number {\n if (a.size === 0 && b.size === 0) return 1;\n let intersection = 0;\n for (const token of a) {\n if (b.has(token)) intersection++;\n }\n const union = a.size + b.size - intersection;\n return union === 0 ? 0 : intersection / union;\n}\n\n/**\n * Build a text fingerprint from an observation for similarity matching.\n */\nfunction observationFingerprint(obs: Observation): string {\n return [obs.title, obs.narrative, ...obs.facts, ...obs.concepts].join(' ');\n}\n\n/** A cluster of similar observations to be merged */\nexport interface ConsolidationCluster {\n /** IDs of observations in this cluster */\n ids: number[];\n /** Titles of observations in this cluster */\n titles: string[];\n /** Average pairwise similarity */\n similarity: number;\n /** The entity these belong to */\n entityName: string;\n /** The observation type */\n type: string;\n}\n\n/** Result of a consolidation run */\nexport interface ConsolidationResult {\n /** Number of clusters found */\n clustersFound: number;\n /** Number of observations merged */\n observationsMerged: number;\n /** Number of observations after consolidation */\n observationsAfter: number;\n /** Details of each merge */\n merges: Array<{\n clusterId: number;\n mergedIds: number[];\n resultTitle: string;\n factCount: number;\n }>;\n}\n\n/**\n * Find clusters of similar observations that could be consolidated.\n * Does NOT modify data — use this for preview / dry run.\n */\nexport async function findConsolidationCandidates(\n projectDir: string,\n projectId: string,\n opts?: { threshold?: number; limit?: number },\n): Promise<ConsolidationCluster[]> {\n const threshold = opts?.threshold ?? DEFAULT_SIMILARITY_THRESHOLD;\n const limit = opts?.limit ?? MAX_BATCH_SIZE;\n\n const allObs = (await loadObservationsJson(projectDir)) as Observation[];\n const projectObs = allObs\n .filter(o => o.projectId === projectId)\n .slice(0, limit);\n\n if (projectObs.length < MIN_CLUSTER_SIZE) return [];\n\n // Group by entity + type\n const groups = new Map<string, Observation[]>();\n for (const obs of projectObs) {\n const key = `${obs.entityName}::${obs.type}`;\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(obs);\n }\n\n const clusters: ConsolidationCluster[] = [];\n\n for (const [, group] of groups) {\n if (group.length < MIN_CLUSTER_SIZE) continue;\n\n // Pre-compute fingerprints\n const fingerprints = group.map(obs => ({\n obs,\n tokens: tokenize(observationFingerprint(obs)),\n }));\n\n // Track which observations are already clustered\n const clustered = new Set<number>();\n\n // Greedy clustering: for each unclustered obs, find similar ones\n for (let i = 0; i < fingerprints.length; i++) {\n if (clustered.has(fingerprints[i].obs.id)) continue;\n\n const cluster: Observation[] = [fingerprints[i].obs];\n let totalSim = 0;\n let simCount = 0;\n\n for (let j = i + 1; j < fingerprints.length; j++) {\n if (clustered.has(fingerprints[j].obs.id)) continue;\n\n const sim = jaccardSimilarity(fingerprints[i].tokens, fingerprints[j].tokens);\n if (sim >= threshold) {\n cluster.push(fingerprints[j].obs);\n totalSim += sim;\n simCount++;\n }\n }\n\n if (cluster.length >= MIN_CLUSTER_SIZE) {\n for (const obs of cluster) clustered.add(obs.id);\n clusters.push({\n ids: cluster.map(o => o.id),\n titles: cluster.map(o => o.title),\n similarity: simCount > 0 ? totalSim / simCount : 0,\n entityName: cluster[0].entityName,\n type: cluster[0].type,\n });\n }\n }\n }\n\n return clusters;\n}\n\n/**\n * Execute consolidation — merge clusters into single observations.\n *\n * For each cluster:\n * 1. Keep the most recent observation as the \"primary\"\n * 2. Merge facts, files, concepts from all members (deduplicated)\n * 3. Create a consolidated narrative\n * 4. Remove the other members\n */\nexport async function executeConsolidation(\n projectDir: string,\n projectId: string,\n opts?: { threshold?: number; limit?: number },\n): Promise<ConsolidationResult> {\n const clusters = await findConsolidationCandidates(projectDir, projectId, opts);\n\n if (clusters.length === 0) {\n const allObs = (await loadObservationsJson(projectDir)) as Observation[];\n return {\n clustersFound: 0,\n observationsMerged: 0,\n observationsAfter: allObs.filter(o => o.projectId === projectId).length,\n merges: [],\n };\n }\n\n const result: ConsolidationResult = {\n clustersFound: clusters.length,\n observationsMerged: 0,\n observationsAfter: 0,\n merges: [],\n };\n\n await withFileLock(projectDir, async () => {\n const allObs = (await loadObservationsJson(projectDir)) as Observation[];\n const obsMap = new Map(allObs.map(o => [o.id, o]));\n const idsToRemove = new Set<number>();\n\n for (let ci = 0; ci < clusters.length; ci++) {\n const cluster = clusters[ci];\n const members = cluster.ids\n .map(id => obsMap.get(id))\n .filter((o): o is Observation => o !== undefined);\n\n if (members.length < MIN_CLUSTER_SIZE) continue;\n\n // Sort by date — most recent first\n members.sort((a, b) =>\n new Date(b.updatedAt || b.createdAt).getTime() -\n new Date(a.updatedAt || a.createdAt).getTime(),\n );\n\n const primary = members[0];\n const others = members.slice(1);\n\n // Merge facts (deduplicated)\n const allFacts = new Set(primary.facts);\n for (const other of others) {\n for (const fact of other.facts) allFacts.add(fact);\n }\n\n // Merge files (deduplicated, case-insensitive)\n const fileSet = new Set(primary.filesModified.map(f => f.toLowerCase()));\n const allFiles = [...primary.filesModified];\n for (const other of others) {\n for (const f of other.filesModified) {\n if (!fileSet.has(f.toLowerCase())) {\n fileSet.add(f.toLowerCase());\n allFiles.push(f);\n }\n }\n }\n\n // Merge concepts (deduplicated)\n const conceptSet = new Set(primary.concepts);\n for (const other of others) {\n for (const c of other.concepts) conceptSet.add(c);\n }\n\n // Build consolidated narrative\n const narrativeParts = [primary.narrative];\n for (const other of others) {\n if (other.narrative !== primary.narrative) {\n narrativeParts.push(`[Consolidated from #${other.id}] ${other.narrative}`);\n }\n }\n\n // Update primary\n primary.facts = [...allFacts];\n primary.filesModified = allFiles;\n primary.concepts = [...conceptSet];\n primary.narrative = narrativeParts.join('\\n\\n');\n primary.updatedAt = new Date().toISOString();\n primary.revisionCount = (primary.revisionCount ?? 1) + others.length;\n\n // Mark others for removal\n for (const other of others) {\n idsToRemove.add(other.id);\n }\n\n result.observationsMerged += others.length;\n result.merges.push({\n clusterId: ci,\n mergedIds: cluster.ids,\n resultTitle: primary.title,\n factCount: primary.facts.length,\n });\n }\n\n // Remove merged observations\n const remaining = allObs.filter(o => !idsToRemove.has(o.id));\n await saveObservationsJson(projectDir, remaining);\n\n result.observationsAfter = remaining.filter(o => o.projectId === projectId).length;\n });\n\n return result;\n}\n","/**\n * Export/Import Engine\n *\n * Enables team collaboration by exporting and importing Memorix data.\n *\n * Export formats:\n * - JSON: Full fidelity, machine-readable\n * - Markdown: Human-readable, great for sharing in PRs/docs\n *\n * Import: JSON format only (full fidelity restore)\n */\n\nimport type { Observation } from '../types.js';\nimport type { Session } from '../types.js';\nimport { loadObservationsJson, saveObservationsJson, loadIdCounter, saveIdCounter } from '../store/persistence.js';\nimport { loadSessionsJson, saveSessionsJson } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\n/** Export package structure */\nexport interface MemorixExport {\n version: string;\n exportedAt: string;\n projectId: string;\n observations: Observation[];\n sessions: Session[];\n stats: {\n observationCount: number;\n sessionCount: number;\n typeBreakdown: Record<string, number>;\n };\n}\n\nconst OBSERVATION_ICONS: Record<string, string> = {\n 'session-request': '🎯', 'gotcha': '🔴', 'problem-solution': '🟡',\n 'how-it-works': '🔵', 'what-changed': '🟢', 'discovery': '🟣',\n 'why-it-exists': '🟠', 'decision': '🟤', 'trade-off': '⚖️',\n};\n\n/**\n * Export project data as JSON.\n */\nexport async function exportAsJson(\n projectDir: string,\n projectId: string,\n): Promise<MemorixExport> {\n const allObs = (await loadObservationsJson(projectDir)) as Observation[];\n const allSessions = (await loadSessionsJson(projectDir)) as Session[];\n\n const projectObs = allObs.filter(o => o.projectId === projectId);\n const projectSessions = allSessions.filter(s => s.projectId === projectId);\n\n // Type breakdown\n const typeBreakdown: Record<string, number> = {};\n for (const obs of projectObs) {\n typeBreakdown[obs.type] = (typeBreakdown[obs.type] ?? 0) + 1;\n }\n\n return {\n version: '0.9.0',\n exportedAt: new Date().toISOString(),\n projectId,\n observations: projectObs,\n sessions: projectSessions,\n stats: {\n observationCount: projectObs.length,\n sessionCount: projectSessions.length,\n typeBreakdown,\n },\n };\n}\n\n/**\n * Export project data as human-readable Markdown.\n */\nexport async function exportAsMarkdown(\n projectDir: string,\n projectId: string,\n): Promise<string> {\n const data = await exportAsJson(projectDir, projectId);\n const lines: string[] = [];\n\n lines.push(`# Memorix Export: ${projectId}`);\n lines.push(`Exported: ${data.exportedAt}`);\n lines.push(`Observations: ${data.stats.observationCount} | Sessions: ${data.stats.sessionCount}`);\n lines.push('');\n\n // Type breakdown\n if (Object.keys(data.stats.typeBreakdown).length > 0) {\n lines.push('## Type Distribution');\n for (const [type, count] of Object.entries(data.stats.typeBreakdown).sort((a, b) => b[1] - a[1])) {\n const icon = OBSERVATION_ICONS[type] ?? '❓';\n lines.push(`- ${icon} ${type}: ${count}`);\n }\n lines.push('');\n }\n\n // Sessions\n if (data.sessions.length > 0) {\n lines.push('## Sessions');\n for (const s of data.sessions) {\n const status = s.status === 'active' ? '🟢' : '✅';\n const agent = s.agent ? ` [${s.agent}]` : '';\n lines.push(`### ${status} ${s.id}${agent}`);\n lines.push(`Started: ${s.startedAt}${s.endedAt ? ` | Ended: ${s.endedAt}` : ''}`);\n if (s.summary) {\n lines.push('');\n lines.push(s.summary);\n }\n lines.push('');\n }\n }\n\n // Observations grouped by entity\n const byEntity = new Map<string, Observation[]>();\n for (const obs of data.observations) {\n if (!byEntity.has(obs.entityName)) byEntity.set(obs.entityName, []);\n byEntity.get(obs.entityName)!.push(obs);\n }\n\n lines.push('## Observations');\n for (const [entity, observations] of byEntity) {\n lines.push(`### ${entity}`);\n for (const obs of observations) {\n const icon = OBSERVATION_ICONS[obs.type] ?? '❓';\n lines.push(`#### ${icon} #${obs.id} ${obs.title}`);\n lines.push(`Type: ${obs.type} | Created: ${obs.createdAt}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ''}${obs.revisionCount && obs.revisionCount > 1 ? ` | Rev: ${obs.revisionCount}` : ''}`);\n lines.push('');\n lines.push(obs.narrative);\n if (obs.facts.length > 0) {\n lines.push('');\n lines.push('**Facts:**');\n for (const f of obs.facts) lines.push(`- ${f}`);\n }\n if (obs.filesModified.length > 0) {\n lines.push('');\n lines.push(`**Files:** ${obs.filesModified.join(', ')}`);\n }\n lines.push('');\n }\n }\n\n return lines.join('\\n');\n}\n\n/**\n * Import observations and sessions from a JSON export.\n * Re-assigns IDs to avoid conflicts with existing data.\n */\nexport async function importFromJson(\n projectDir: string,\n data: MemorixExport,\n): Promise<{ observationsImported: number; sessionsImported: number; skipped: number }> {\n let imported = 0;\n let sessionsImported = 0;\n let skipped = 0;\n\n await withFileLock(projectDir, async () => {\n const existingObs = (await loadObservationsJson(projectDir)) as Observation[];\n const existingSessions = (await loadSessionsJson(projectDir)) as Session[];\n let nextId = await loadIdCounter(projectDir);\n\n // Build set of existing topicKey+projectId for dedup\n const existingTopicKeys = new Set(\n existingObs\n .filter(o => o.topicKey)\n .map(o => `${o.projectId}::${o.topicKey}`),\n );\n\n // Import observations\n for (const obs of data.observations) {\n // Skip if topicKey already exists (dedup)\n if (obs.topicKey && existingTopicKeys.has(`${obs.projectId}::${obs.topicKey}`)) {\n skipped++;\n continue;\n }\n\n const newObs = { ...obs, id: nextId++ };\n existingObs.push(newObs);\n imported++;\n }\n\n // Import sessions (skip duplicates by ID)\n const existingSessionIds = new Set(existingSessions.map(s => s.id));\n for (const session of data.sessions) {\n if (!existingSessionIds.has(session.id)) {\n existingSessions.push(session);\n sessionsImported++;\n }\n }\n\n await saveObservationsJson(projectDir, existingObs);\n await saveIdCounter(projectDir, nextId);\n await saveSessionsJson(projectDir, existingSessions);\n });\n\n return { observationsImported: imported, sessionsImported, skipped };\n}\n","/**\r\n * Memorix Dashboard Server\r\n *\r\n * Lightweight HTTP server that serves:\r\n * - REST API endpoints for reading memorix data\r\n * - Static frontend files (SPA)\r\n *\r\n * Zero external dependencies — uses Node.js built-in http module.\r\n */\r\n\r\nimport { createServer, type IncomingMessage, type ServerResponse } from 'node:http';\r\nimport { promises as fs } from 'node:fs';\r\nimport path from 'node:path';\r\nimport { exec } from 'node:child_process';\r\n\r\nimport { loadGraphJsonl, saveGraphJsonl, loadObservationsJson, saveObservationsJson, loadIdCounter, getBaseDataDir, loadSessionsJson } from '../store/persistence.js';\r\nimport { withFileLock } from '../store/file-lock.js';\r\n\r\n// MIME types for static file serving\r\nconst MIME_TYPES: Record<string, string> = {\r\n '.html': 'text/html; charset=utf-8',\r\n '.css': 'text/css; charset=utf-8',\r\n '.js': 'application/javascript; charset=utf-8',\r\n '.json': 'application/json; charset=utf-8',\r\n '.svg': 'image/svg+xml',\r\n '.png': 'image/png',\r\n '.ico': 'image/x-icon',\r\n};\r\n\r\n/**\r\n * Send a JSON response\r\n */\r\nfunction sendJson(res: ServerResponse, data: unknown, status = 200) {\r\n res.writeHead(status, {\r\n 'Content-Type': 'application/json; charset=utf-8',\r\n 'Access-Control-Allow-Origin': '*',\r\n });\r\n res.end(JSON.stringify(data));\r\n}\r\n\r\n/**\r\n * Send an error response\r\n */\r\nfunction sendError(res: ServerResponse, message: string, status = 500) {\r\n sendJson(res, { error: message }, status);\r\n}\r\n\r\n/**\r\n * Filter observations by projectId\r\n */\r\nfunction filterByProject<T extends { projectId?: string }>(items: T[], projectId: string): T[] {\r\n return items.filter(item => item.projectId === projectId);\r\n}\r\n\r\n/**\r\n * API route handlers\r\n */\r\nasync function handleApi(\r\n req: IncomingMessage,\r\n res: ServerResponse,\r\n dataDir: string,\r\n projectId: string,\r\n projectName: string,\r\n baseDir: string,\r\n) {\r\n const url = new URL(req.url || '/', `http://${req.headers.host}`);\r\n const apiPath = url.pathname.replace('/api', '');\r\n\r\n // Support ?project=xxx to switch view to another project\r\n // In flat storage, all projects share the same dataDir — only the projectId filter changes\r\n const requestedProject = url.searchParams.get('project');\r\n let effectiveDataDir = dataDir;\r\n let effectiveProjectId = projectId;\r\n let effectiveProjectName = projectName;\r\n if (requestedProject && requestedProject !== projectId) {\r\n effectiveDataDir = baseDir; // flat storage: all data in one dir\r\n effectiveProjectId = requestedProject;\r\n effectiveProjectName = requestedProject.split('/').pop() || requestedProject;\r\n }\r\n\r\n try {\r\n switch (apiPath) {\r\n case '/projects': {\r\n // List all unique project IDs from observations data (flat storage)\r\n // Deduplicate using alias registry — aliased IDs are merged under canonical\r\n try {\r\n const allObs = await loadObservationsJson(baseDir) as Array<{ projectId?: string }>;\r\n const projectSet = new Map<string, number>();\r\n for (const obs of allObs) {\r\n if (obs.projectId) {\r\n projectSet.set(obs.projectId, (projectSet.get(obs.projectId) || 0) + 1);\r\n }\r\n }\r\n\r\n // Merge aliased project IDs into their canonical form\r\n let mergedSet = projectSet;\r\n try {\r\n const { getCanonicalId } = await import('../project/aliases.js');\r\n mergedSet = new Map<string, number>();\r\n for (const [id, count] of projectSet) {\r\n const canonical = await getCanonicalId(id);\r\n mergedSet.set(canonical, (mergedSet.get(canonical) || 0) + count);\r\n }\r\n } catch { /* alias module not available, use raw IDs */ }\r\n\r\n const projects = Array.from(mergedSet.entries())\r\n .sort((a, b) => b[1] - a[1]) // Most observations first\r\n .map(([id, count]) => ({\r\n id,\r\n name: id.split('/').pop() || id,\r\n count,\r\n isCurrent: id === projectId,\r\n }));\r\n sendJson(res, projects);\r\n } catch {\r\n sendJson(res, []);\r\n }\r\n break;\r\n }\r\n\r\n case '/project': {\r\n sendJson(res, { id: effectiveProjectId, name: effectiveProjectName });\r\n break;\r\n }\r\n\r\n case '/graph': {\r\n const graph = await loadGraphJsonl(effectiveDataDir);\r\n sendJson(res, graph);\r\n break;\r\n }\r\n\r\n case '/observations': {\r\n const allObs = await loadObservationsJson(effectiveDataDir);\r\n const observations = filterByProject(allObs as Array<{ projectId?: string }>, effectiveProjectId);\r\n sendJson(res, observations);\r\n break;\r\n }\r\n\r\n case '/sessions': {\r\n const allSessions = await loadSessionsJson(effectiveDataDir);\r\n const sessions = filterByProject(allSessions as Array<{ projectId?: string }>, effectiveProjectId);\r\n sendJson(res, sessions);\r\n break;\r\n }\r\n\r\n case '/stats': {\r\n const graph = await loadGraphJsonl(effectiveDataDir);\r\n const allObs = await loadObservationsJson(effectiveDataDir);\r\n const observations = filterByProject(allObs as Array<{ projectId?: string; type?: string; id?: number; createdAt?: string; title?: string; entityName?: string }>, effectiveProjectId);\r\n const nextId = await loadIdCounter(effectiveDataDir);\r\n\r\n // Type counts\r\n const typeCounts: Record<string, number> = {};\r\n for (const obs of observations) {\r\n const t = obs.type || 'unknown';\r\n typeCounts[t] = (typeCounts[t] || 0) + 1;\r\n }\r\n\r\n // Recent observations (last 10)\r\n const sorted = [...observations]\r\n .sort((a, b) => (b.id || 0) - (a.id || 0))\r\n .slice(0, 10);\r\n\r\n // Embedding provider status\r\n let embeddingStatus = { enabled: false, provider: '', dimensions: 0 };\r\n try {\r\n const { getEmbeddingProvider } = await import('../embedding/provider.js');\r\n const embProvider = await getEmbeddingProvider();\r\n embeddingStatus = {\r\n enabled: embProvider !== null,\r\n provider: embProvider?.name || '',\r\n dimensions: embProvider?.dimensions || 0,\r\n };\r\n } catch { /* embedding module not available */ }\r\n\r\n sendJson(res, {\r\n entities: graph.entities.length,\r\n relations: graph.relations.length,\r\n observations: observations.length,\r\n nextId,\r\n typeCounts,\r\n recentObservations: sorted,\r\n embedding: embeddingStatus,\r\n });\r\n break;\r\n }\r\n\r\n case '/retention': {\r\n const allObs = await loadObservationsJson(effectiveDataDir) as Array<{\r\n id?: number;\r\n title?: string;\r\n type?: string;\r\n importance?: number;\r\n accessCount?: number;\r\n lastAccessedAt?: string;\r\n createdAt?: string;\r\n entityName?: string;\r\n projectId?: string;\r\n }>;\r\n const observations = filterByProject(allObs, effectiveProjectId);\r\n\r\n const now = Date.now();\r\n const scored = observations.map((obs) => {\r\n const age = now - new Date(obs.createdAt || now).getTime();\r\n const ageHours = age / (1000 * 60 * 60);\r\n const importance = obs.importance ?? 5;\r\n const accessCount = obs.accessCount ?? 0;\r\n\r\n // Exponential decay: score = importance * e^(-λt) + access_bonus\r\n const lambda = 0.01;\r\n const decayScore = importance * Math.exp(-lambda * ageHours);\r\n const accessBonus = Math.min(accessCount * 0.5, 3);\r\n const score = Math.min(decayScore + accessBonus, 10);\r\n\r\n // Immune if importance >= 8 or type is 'gotcha' or 'decision'\r\n const isImmune = importance >= 8 || obs.type === 'gotcha' || obs.type === 'decision';\r\n\r\n return {\r\n id: obs.id,\r\n title: obs.title,\r\n type: obs.type,\r\n entityName: obs.entityName,\r\n score: Math.round(score * 100) / 100,\r\n isImmune,\r\n ageHours: Math.round(ageHours * 10) / 10,\r\n accessCount,\r\n };\r\n });\r\n\r\n // Sort by score descending\r\n scored.sort((a, b) => b.score - a.score);\r\n\r\n const activeCount = scored.filter((s) => s.score >= 3).length;\r\n const staleCount = scored.filter((s) => s.score < 3 && s.score >= 1).length;\r\n const archiveCount = scored.filter((s) => s.score < 1).length;\r\n const immuneCount = scored.filter((s) => s.isImmune).length;\r\n\r\n sendJson(res, {\r\n summary: { active: activeCount, stale: staleCount, archive: archiveCount, immune: immuneCount },\r\n items: scored,\r\n });\r\n break;\r\n }\r\n\r\n default: {\r\n // Handle dynamic routes\r\n const deleteMatch = apiPath.match(/^\\/observations\\/(\\d+)$/);\r\n if (deleteMatch && req.method === 'DELETE') {\r\n const obsId = parseInt(deleteMatch[1], 10);\r\n await withFileLock(effectiveDataDir, async () => {\r\n const allObs = await loadObservationsJson(effectiveDataDir) as Array<{ id?: number;[k: string]: unknown }>;\r\n const idx = allObs.findIndex(o => o.id === obsId);\r\n if (idx === -1) {\r\n sendError(res, 'Observation not found', 404);\r\n } else {\r\n allObs.splice(idx, 1);\r\n await saveObservationsJson(effectiveDataDir, allObs);\r\n\r\n // Sync: clean up graph entity references for this observation\r\n try {\r\n const graph = await loadGraphJsonl(effectiveDataDir);\r\n const prefix = `[#${obsId}] `;\r\n let graphChanged = false;\r\n for (const entity of graph.entities) {\r\n const before = entity.observations.length;\r\n entity.observations = entity.observations.filter(o => !o.startsWith(prefix));\r\n if (entity.observations.length < before) graphChanged = true;\r\n }\r\n if (graphChanged) {\r\n await saveGraphJsonl(effectiveDataDir, graph.entities, graph.relations);\r\n }\r\n } catch { /* graph sync is best-effort */ }\r\n\r\n sendJson(res, { ok: true, deleted: obsId });\r\n }\r\n });\r\n break;\r\n }\r\n\r\n if (apiPath === '/export') {\r\n const graph = await loadGraphJsonl(effectiveDataDir);\r\n const allObs = await loadObservationsJson(effectiveDataDir);\r\n const observations = filterByProject(allObs as Array<{ projectId?: string }>, effectiveProjectId);\r\n const nextId = await loadIdCounter(effectiveDataDir);\r\n const exportData = {\r\n project: { id: effectiveProjectId, name: effectiveProjectName },\r\n exportedAt: new Date().toISOString(),\r\n graph,\r\n observations,\r\n nextId,\r\n };\r\n res.writeHead(200, {\r\n 'Content-Type': 'application/json',\r\n 'Content-Disposition': `attachment; filename=\"memorix-${effectiveProjectId.replace(/\\//g, '-')}-export.json\"`,\r\n });\r\n res.end(JSON.stringify(exportData, null, 2));\r\n break;\r\n }\r\n\r\n sendError(res, 'Not found', 404);\r\n }\r\n }\r\n } catch (err) {\r\n const message = err instanceof Error ? err.message : 'Unknown error';\r\n sendError(res, message);\r\n }\r\n}\r\n\r\n/**\r\n * Serve static files from the dashboard/static directory\r\n */\r\nasync function serveStatic(req: IncomingMessage, res: ServerResponse, staticDir: string) {\r\n let urlPath = new URL(req.url || '/', `http://${req.headers.host}`).pathname;\r\n\r\n // SPA: serve index.html for all non-file routes\r\n if (urlPath === '/' || !urlPath.includes('.')) {\r\n urlPath = '/index.html';\r\n }\r\n\r\n const filePath = path.join(staticDir, urlPath);\r\n\r\n // Security: prevent directory traversal\r\n if (!filePath.startsWith(staticDir)) {\r\n sendError(res, 'Forbidden', 403);\r\n return;\r\n }\r\n\r\n try {\r\n const data = await fs.readFile(filePath);\r\n const ext = path.extname(filePath);\r\n res.writeHead(200, {\r\n 'Content-Type': MIME_TYPES[ext] || 'application/octet-stream',\r\n 'Cache-Control': 'no-cache',\r\n });\r\n res.end(data);\r\n } catch {\r\n // Fallback to index.html for SPA routing\r\n try {\r\n const indexData = await fs.readFile(path.join(staticDir, 'index.html'));\r\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\r\n res.end(indexData);\r\n } catch {\r\n sendError(res, 'Not found', 404);\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Start the dashboard server\r\n */\r\n\r\n/** Cross-platform open URL in default browser */\r\nfunction openBrowser(url: string) {\r\n const cmd =\r\n process.platform === 'win32' ? `start \"\" \"${url}\"` :\r\n process.platform === 'darwin' ? `open \"${url}\"` :\r\n `xdg-open \"${url}\"`;\r\n exec(cmd, () => { /* ignore errors */ });\r\n}\r\n\r\n/** Mutable dashboard state — updated at runtime when project changes */\r\ninterface DashboardState {\r\n projectId: string;\r\n projectName: string;\r\n dataDir: string;\r\n}\r\n\r\n/** Optional team collaboration instances passed from MCP server */\r\nexport interface TeamInstances {\r\n registry: { listAgents: (filter?: any) => any[]; getActiveCount: () => number; getAgent: (id: string) => any };\r\n fileLocks: { listLocks: (agentId?: string) => any[]; cleanExpired: () => void };\r\n taskManager: { list: (filter?: any) => any[]; getAvailable: () => any[] };\r\n messageBus: { getUnreadCount: (agentId: string) => number };\r\n}\r\n\r\n/** Read full POST body as string */\r\nfunction readBody(req: IncomingMessage): Promise<string> {\r\n return new Promise((resolve, reject) => {\r\n const chunks: Buffer[] = [];\r\n req.on('data', (c: Buffer) => chunks.push(c));\r\n req.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8')));\r\n req.on('error', reject);\r\n });\r\n}\r\n\r\nexport async function startDashboard(\r\n dataDir: string,\r\n port: number,\r\n staticDir: string,\r\n projectId: string,\r\n projectName: string,\r\n autoOpen = true,\r\n teamInstances?: TeamInstances,\r\n): Promise<void> {\r\n const resolvedStaticDir = staticDir;\r\n // Derive baseDir from dataDir (parent directory of project-specific dir)\r\n const baseDir = getBaseDataDir();\r\n\r\n // Mutable state — can be updated via /api/set-current-project\r\n const state: DashboardState = { projectId, projectName, dataDir };\r\n\r\n const server = createServer(async (req, res) => {\r\n const url = req.url || '/';\r\n\r\n // POST /api/set-current-project — update the dashboard's current project\r\n // In flat storage, switching project only changes the projectId filter, not the data dir\r\n if (url.startsWith('/api/set-current-project') && req.method === 'POST') {\r\n try {\r\n const body = JSON.parse(await readBody(req));\r\n if (body.projectId) {\r\n state.projectId = body.projectId;\r\n state.projectName = body.projectName || body.projectId.split('/').pop() || body.projectId;\r\n state.dataDir = baseDir; // flat storage: always use base dir\r\n console.error(`[dashboard] Switched current project to: ${state.projectId}`);\r\n sendJson(res, { ok: true, projectId: state.projectId, projectName: state.projectName });\r\n } else {\r\n sendError(res, 'Missing projectId in body', 400);\r\n }\r\n } catch {\r\n sendError(res, 'Invalid JSON body', 400);\r\n }\r\n return;\r\n }\r\n\r\n if (url.startsWith('/api/team') && teamInstances) {\r\n try {\r\n teamInstances.fileLocks.cleanExpired();\r\n const agents = teamInstances.registry.listAgents();\r\n const locks = teamInstances.fileLocks.listLocks();\r\n const tasks = teamInstances.taskManager.list();\r\n const available = teamInstances.taskManager.getAvailable();\r\n sendJson(res, {\r\n agents: agents.map((a: any) => ({\r\n ...a,\r\n unread: teamInstances!.messageBus.getUnreadCount(a.id),\r\n })),\r\n activeCount: teamInstances.registry.getActiveCount(),\r\n locks,\r\n tasks,\r\n availableTasks: available.length,\r\n });\r\n } catch {\r\n sendJson(res, { agents: [], activeCount: 0, locks: [], tasks: [], availableTasks: 0 });\r\n }\r\n return;\r\n }\r\n\r\n if (url.startsWith('/api/')) {\r\n await handleApi(req, res, state.dataDir, state.projectId, state.projectName, baseDir);\r\n } else {\r\n await serveStatic(req, res, resolvedStaticDir);\r\n }\r\n });\r\n\r\n return new Promise((resolve, reject) => {\r\n server.on('error', (err: NodeJS.ErrnoException) => {\r\n if (err.code === 'EADDRINUSE') {\r\n console.error(`Port ${port} is already in use. Try: memorix dashboard --port ${port + 1}`);\r\n reject(err);\r\n } else {\r\n reject(err);\r\n }\r\n });\r\n\r\n server.listen(port, () => {\r\n const url = `http://localhost:${port}`;\r\n console.error(`\\n Memorix Dashboard`);\r\n console.error(` ───────────────────────`);\r\n console.error(` Project: ${projectName} (${projectId})`);\r\n console.error(` Local: ${url}`);\r\n console.error(` Data dir: ${dataDir}`);\r\n console.error(`\\n Press Ctrl+C to stop\\n`);\r\n\r\n // Auto-open browser\r\n if (autoOpen) openBrowser(url);\r\n\r\n resolve();\r\n });\r\n });\r\n}\r\n","/**\n * Agent Registry — Tracks agents in a multi-agent team\n *\n * In-memory registry shared across all MCP sessions on the same HTTP server.\n * Each agent joins with a name, optional role, and capabilities.\n * Registry supports heartbeat for liveness detection.\n */\n\nimport { randomUUID } from 'node:crypto';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface AgentJoinInput {\n name: string;\n role?: string;\n capabilities?: string[];\n}\n\nexport interface AgentInfo {\n id: string;\n name: string;\n role?: string;\n capabilities: string[];\n status: 'active' | 'inactive';\n joinedAt: Date;\n lastSeenAt: Date;\n leftAt?: Date;\n}\n\nexport interface AgentListFilter {\n status?: 'active' | 'inactive';\n}\n\n// ─── Registry ────────────────────────────────────────────────────────\n\nexport class AgentRegistry {\n private agents = new Map<string, AgentInfo>();\n private nameIndex = new Map<string, string>(); // name → id\n\n /**\n * Register an agent. If an agent with the same name already exists,\n * reactivate it with updated info instead of creating a duplicate.\n */\n join(input: AgentJoinInput): AgentInfo {\n const existing = this.nameIndex.get(input.name);\n if (existing) {\n const agent = this.agents.get(existing)!;\n agent.role = input.role;\n agent.capabilities = input.capabilities ?? agent.capabilities;\n agent.status = 'active';\n agent.lastSeenAt = new Date();\n delete agent.leftAt;\n return { ...agent };\n }\n\n const id = randomUUID();\n const now = new Date();\n const agent: AgentInfo = {\n id,\n name: input.name,\n role: input.role,\n capabilities: input.capabilities ?? [],\n status: 'active',\n joinedAt: now,\n lastSeenAt: now,\n };\n\n this.agents.set(id, agent);\n this.nameIndex.set(input.name, id);\n return { ...agent };\n }\n\n /**\n * Mark an agent as inactive. Returns false if agent not found.\n */\n leave(agentId: string): boolean {\n const agent = this.agents.get(agentId);\n if (!agent) return false;\n\n agent.status = 'inactive';\n agent.leftAt = new Date();\n return true;\n }\n\n /**\n * Get info for a specific agent. Returns null if not found.\n */\n getAgent(agentId: string): AgentInfo | null {\n const agent = this.agents.get(agentId);\n return agent ? { ...agent } : null;\n }\n\n /**\n * List agents, optionally filtered by status.\n */\n listAgents(filter?: AgentListFilter): AgentInfo[] {\n const all = [...this.agents.values()];\n if (filter?.status) {\n return all.filter(a => a.status === filter.status).map(a => ({ ...a }));\n }\n return all.map(a => ({ ...a }));\n }\n\n /**\n * Update lastSeenAt for an agent. Returns false if not found.\n */\n heartbeat(agentId: string): boolean {\n const agent = this.agents.get(agentId);\n if (!agent) return false;\n agent.lastSeenAt = new Date();\n return true;\n }\n\n /**\n * Count of currently active agents.\n */\n getActiveCount(): number {\n let count = 0;\n for (const agent of this.agents.values()) {\n if (agent.status === 'active') count++;\n }\n return count;\n }\n\n /** Serialize state for file persistence */\n serialize(): { agents: Record<string, unknown>; nameIndex: Record<string, string> } {\n const agents: Record<string, unknown> = {};\n for (const [id, a] of this.agents) {\n agents[id] = {\n ...a,\n joinedAt: a.joinedAt.toISOString(),\n lastSeenAt: a.lastSeenAt.toISOString(),\n leftAt: a.leftAt?.toISOString() ?? null,\n };\n }\n return { agents, nameIndex: Object.fromEntries(this.nameIndex) };\n }\n\n /** Hydrate state from file persistence */\n hydrate(data: { agents?: Record<string, any>; nameIndex?: Record<string, string> }): void {\n this.agents.clear();\n this.nameIndex.clear();\n if (!data?.agents) return;\n for (const [id, raw] of Object.entries(data.agents)) {\n this.agents.set(id, {\n ...raw,\n joinedAt: new Date(raw.joinedAt),\n lastSeenAt: new Date(raw.lastSeenAt),\n leftAt: raw.leftAt ? new Date(raw.leftAt) : undefined,\n });\n }\n if (data.nameIndex) {\n for (const [name, id] of Object.entries(data.nameIndex)) {\n this.nameIndex.set(name, id);\n }\n }\n }\n}\n","/**\n * Message Bus — Agent-to-agent communication\n *\n * In-memory message queue for team coordination.\n * Messages are temporary (not persisted as observations).\n * Supports direct send, broadcast, inbox retrieval, and read tracking.\n */\n\nimport { randomUUID } from 'node:crypto';\nimport type { AgentRegistry } from './registry.js';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport type MessageType = 'request' | 'response' | 'info' | 'announcement' | 'contract' | 'error';\n\nexport interface MessageSendInput {\n from: string;\n to: string;\n type: MessageType;\n content: string;\n}\n\nexport interface MessageBroadcastInput {\n from: string;\n type: MessageType;\n content: string;\n}\n\nexport interface Message {\n id: string;\n from: string;\n to: string;\n type: MessageType;\n content: string;\n timestamp: Date;\n read: boolean;\n}\n\n// ─── Message Bus ─────────────────────────────────────────────────────\n\n/** Max messages per inbox. Oldest read messages are evicted first. */\nconst MAX_INBOX_SIZE = 200;\n/** Max message content length in bytes */\nconst MAX_CONTENT_LENGTH = 10_000;\n\nexport class MessageBus {\n private inboxes = new Map<string, Message[]>();\n private registry: AgentRegistry;\n\n constructor(registry: AgentRegistry) {\n this.registry = registry;\n }\n\n /**\n * Send a message to a specific agent.\n * Throws if receiver is unknown.\n */\n send(input: MessageSendInput): Message {\n const receiver = this.registry.getAgent(input.to);\n if (!receiver) {\n throw new Error(`Unknown receiver agent: ${input.to}`);\n }\n if (receiver.status !== 'active') {\n throw new Error(`Receiver agent is inactive: ${receiver.name}`);\n }\n\n const msg: Message = {\n id: randomUUID(),\n from: input.from,\n to: input.to,\n type: input.type,\n content: input.content,\n timestamp: new Date(),\n read: false,\n };\n\n const inbox = this.inboxes.get(input.to) ?? [];\n inbox.push(msg);\n\n // Evict oldest read messages if inbox exceeds limit\n if (inbox.length > MAX_INBOX_SIZE) {\n const readIndices: number[] = [];\n for (let i = 0; i < inbox.length; i++) {\n if (inbox[i].read) readIndices.push(i);\n }\n // Remove oldest read messages first\n const toRemove = inbox.length - MAX_INBOX_SIZE;\n for (let i = Math.min(toRemove, readIndices.length) - 1; i >= 0; i--) {\n inbox.splice(readIndices[i], 1);\n }\n // If still over limit, remove oldest unread\n while (inbox.length > MAX_INBOX_SIZE) {\n inbox.shift();\n }\n }\n\n this.inboxes.set(input.to, inbox);\n return msg;\n }\n\n /**\n * Broadcast a message to all active agents except the sender.\n */\n broadcast(input: MessageBroadcastInput): Message[] {\n const activeAgents = this.registry.listAgents({ status: 'active' });\n const messages: Message[] = [];\n\n for (const agent of activeAgents) {\n if (agent.id === input.from) continue;\n\n const msg = this.send({\n from: input.from,\n to: agent.id,\n type: input.type,\n content: input.content,\n });\n messages.push(msg);\n }\n\n return messages;\n }\n\n /**\n * Get all messages in an agent's inbox (both read and unread).\n */\n getInbox(agentId: string): Message[] {\n return [...(this.inboxes.get(agentId) ?? [])];\n }\n\n /**\n * Mark specific messages as read.\n */\n markRead(agentId: string, messageIds: string[]): number {\n const inbox = this.inboxes.get(agentId);\n if (!inbox) return 0;\n\n const idSet = new Set(messageIds);\n let count = 0;\n for (const msg of inbox) {\n if (idSet.has(msg.id) && !msg.read) {\n msg.read = true;\n count++;\n }\n }\n return count;\n }\n\n /**\n * Count unread messages for an agent.\n */\n getUnreadCount(agentId: string): number {\n const inbox = this.inboxes.get(agentId);\n if (!inbox) return 0;\n return inbox.filter(m => !m.read).length;\n }\n\n /**\n * Remove all read messages from an agent's inbox.\n * Returns the number of messages pruned.\n */\n pruneRead(agentId: string): number {\n const inbox = this.inboxes.get(agentId);\n if (!inbox) return 0;\n const before = inbox.length;\n const unread = inbox.filter(m => !m.read);\n this.inboxes.set(agentId, unread);\n return before - unread.length;\n }\n\n /**\n * Clear all messages for an agent (used on agent leave).\n */\n clearInbox(agentId: string): void {\n this.inboxes.delete(agentId);\n }\n\n /** Max allowed content length */\n static get MAX_CONTENT_LENGTH() { return MAX_CONTENT_LENGTH; }\n\n /** Serialize state for file persistence */\n serialize(): { inboxes: Record<string, unknown[]> } {\n const inboxes: Record<string, unknown[]> = {};\n for (const [agentId, msgs] of this.inboxes) {\n inboxes[agentId] = msgs.map(m => ({\n ...m,\n timestamp: m.timestamp.toISOString(),\n }));\n }\n return { inboxes };\n }\n\n /** Hydrate state from file persistence */\n hydrate(data: { inboxes?: Record<string, any[]> }): void {\n this.inboxes.clear();\n if (!data?.inboxes) return;\n for (const [agentId, msgs] of Object.entries(data.inboxes)) {\n this.inboxes.set(agentId, msgs.map(m => ({\n ...m,\n timestamp: new Date(m.timestamp),\n })));\n }\n }\n}\n","/**\n * File Lock Registry — Advisory file locks for multi-agent coordination\n *\n * Prevents conflicting edits when multiple agents work on the same project.\n * Locks are advisory (not enforced at OS level) with TTL auto-release.\n * Default TTL: 10 minutes. Agents see lock status via session_start injection.\n */\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface LockResult {\n success: boolean;\n lockedBy: string;\n file: string;\n}\n\nexport interface LockInfo {\n file: string;\n lockedBy: string;\n lockedAt: Date;\n expiresAt: Date;\n}\n\nexport interface LockOptions {\n ttlMs?: number;\n}\n\nconst DEFAULT_TTL_MS = 10 * 60 * 1000; // 10 minutes\n\n// ─── Internal Lock Entry ─────────────────────────────────────────────\n\ninterface LockEntry {\n file: string;\n lockedBy: string;\n lockedAt: Date;\n expiresAt: Date;\n}\n\n// ─── Registry ────────────────────────────────────────────────────────\n\nexport class FileLockRegistry {\n private locks = new Map<string, LockEntry>();\n\n /**\n * Attempt to lock a file for an agent.\n * Returns success:true if lock acquired, or success:false with current owner.\n * Same agent re-locking is idempotent (refreshes TTL).\n */\n lock(file: string, agentId: string, options?: LockOptions): LockResult {\n const ttl = options?.ttlMs ?? DEFAULT_TTL_MS;\n\n // Clean expired locks first\n this.cleanExpiredEntry(file);\n\n const existing = this.locks.get(file);\n\n if (existing) {\n if (existing.lockedBy === agentId) {\n // Same agent — refresh TTL\n existing.expiresAt = new Date(Date.now() + ttl);\n return { success: true, lockedBy: agentId, file };\n }\n // Different agent holds the lock\n return { success: false, lockedBy: existing.lockedBy, file };\n }\n\n // No lock — acquire\n const now = new Date();\n this.locks.set(file, {\n file,\n lockedBy: agentId,\n lockedAt: now,\n expiresAt: new Date(now.getTime() + ttl),\n });\n\n return { success: true, lockedBy: agentId, file };\n }\n\n /**\n * Release a lock. Only the owner can release.\n * Returns true if released, false if not found or not owner.\n */\n unlock(file: string, agentId: string): boolean {\n const entry = this.locks.get(file);\n if (!entry) return false;\n if (entry.lockedBy !== agentId) return false;\n\n this.locks.delete(file);\n return true;\n }\n\n /**\n * Get lock status for a specific file. Returns null if unlocked.\n */\n getStatus(file: string): LockInfo | null {\n this.cleanExpiredEntry(file);\n const entry = this.locks.get(file);\n if (!entry) return null;\n return { ...entry };\n }\n\n /**\n * List all active locks, optionally filtered by agent.\n */\n listLocks(agentId?: string): LockInfo[] {\n this.cleanExpired();\n const all = [...this.locks.values()];\n const filtered = agentId ? all.filter(l => l.lockedBy === agentId) : all;\n return filtered.map(l => ({ ...l }));\n }\n\n /**\n * Release all locks held by a specific agent. Returns count released.\n */\n releaseAll(agentId: string): number {\n let count = 0;\n for (const [file, entry] of this.locks) {\n if (entry.lockedBy === agentId) {\n this.locks.delete(file);\n count++;\n }\n }\n return count;\n }\n\n /**\n * Remove all expired locks.\n */\n cleanExpired(): void {\n const now = Date.now();\n for (const [file, entry] of this.locks) {\n if (entry.expiresAt.getTime() <= now) {\n this.locks.delete(file);\n }\n }\n }\n\n /**\n * Check and remove a single expired lock entry.\n */\n private cleanExpiredEntry(file: string): void {\n const entry = this.locks.get(file);\n if (entry && entry.expiresAt.getTime() <= Date.now()) {\n this.locks.delete(file);\n }\n }\n\n /** Serialize state for file persistence */\n serialize(): { locks: Record<string, unknown> } {\n const locks: Record<string, unknown> = {};\n for (const [file, entry] of this.locks) {\n locks[file] = {\n ...entry,\n lockedAt: entry.lockedAt.toISOString(),\n expiresAt: entry.expiresAt.toISOString(),\n };\n }\n return { locks };\n }\n\n /** Hydrate state from file persistence */\n hydrate(data: { locks?: Record<string, any> }): void {\n this.locks.clear();\n if (!data?.locks) return;\n for (const [file, raw] of Object.entries(data.locks)) {\n this.locks.set(file, {\n ...(raw as any),\n lockedAt: new Date((raw as any).lockedAt),\n expiresAt: new Date((raw as any).expiresAt),\n });\n }\n }\n}\n","/**\n * Task Manager — Simple task DAG with dependencies\n *\n * Agents can create tasks, claim them, complete them, and query available work.\n * Dependencies are validated: a task can only be claimed when all deps are completed.\n * Simple JSON format — no complex graph structures.\n */\n\nimport { randomUUID } from 'node:crypto';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed';\n\nexport interface TaskCreateInput {\n description: string;\n deps?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface Task {\n id: string;\n description: string;\n status: TaskStatus;\n deps: string[];\n assignee?: string;\n result?: string;\n metadata?: Record<string, unknown>;\n createdAt: Date;\n updatedAt: Date;\n}\n\nexport interface TaskListFilter {\n status?: TaskStatus;\n assignee?: string;\n}\n\n// ─── Manager ─────────────────────────────────────────────────────────\n\nexport class TaskManager {\n private tasks = new Map<string, Task>();\n\n /**\n * Create a new task. Validates that all dependency IDs exist.\n */\n create(input: TaskCreateInput): Task {\n const deps = input.deps ?? [];\n\n // Validate deps exist\n for (const dep of deps) {\n if (!this.tasks.has(dep)) {\n throw new Error(`Unknown dependency task: ${dep}`);\n }\n }\n\n const now = new Date();\n const task: Task = {\n id: randomUUID(),\n description: input.description,\n status: 'pending',\n deps,\n metadata: input.metadata,\n createdAt: now,\n updatedAt: now,\n };\n\n this.tasks.set(task.id, task);\n return { ...task };\n }\n\n /**\n * Claim a pending task for an agent.\n * Validates: task exists, not claimed by another, all deps completed.\n */\n claim(taskId: string, agentId: string): Task {\n const task = this.tasks.get(taskId);\n if (!task) throw new Error(`Task not found: ${taskId}`);\n\n // Allow same agent to re-claim\n if (task.assignee && task.assignee !== agentId) {\n throw new Error(`Task already claimed by ${task.assignee}`);\n }\n\n // Check all dependencies are completed\n for (const depId of task.deps) {\n const dep = this.tasks.get(depId);\n if (!dep || dep.status !== 'completed') {\n throw new Error(`Cannot claim: dependencies not completed (${depId})`);\n }\n }\n\n task.assignee = agentId;\n task.status = 'in_progress';\n task.updatedAt = new Date();\n return { ...task };\n }\n\n /**\n * Complete a task with a result. Only the assignee can complete,\n * unless allowRescue is true (used when original assignee left).\n */\n complete(taskId: string, agentId: string, result: string, allowRescue = false): Task {\n const task = this.tasks.get(taskId);\n if (!task) throw new Error(`Task not found: ${taskId}`);\n if (!task.assignee) throw new Error(`Task not claimed: ${taskId}`);\n if (task.assignee !== agentId && !allowRescue) {\n throw new Error(`Only assignee ${task.assignee} can complete this task`);\n }\n\n task.assignee = agentId;\n task.status = 'completed';\n task.result = result;\n task.updatedAt = new Date();\n return { ...task };\n }\n\n /**\n * Release all in_progress tasks assigned to a specific agent.\n * Returns them to 'pending' so other agents can claim them.\n */\n releaseByAgent(agentId: string): number {\n let count = 0;\n for (const task of this.tasks.values()) {\n if (task.assignee === agentId && task.status === 'in_progress') {\n task.status = 'pending';\n task.assignee = undefined;\n task.updatedAt = new Date();\n count++;\n }\n }\n return count;\n }\n\n /**\n * List tasks with optional filters.\n */\n list(filter?: TaskListFilter): Task[] {\n let all = [...this.tasks.values()];\n if (filter?.status) {\n all = all.filter(t => t.status === filter.status);\n }\n if (filter?.assignee) {\n all = all.filter(t => t.assignee === filter.assignee);\n }\n return all.map(t => ({ ...t }));\n }\n\n /**\n * Get tasks that are available to be claimed:\n * - status is 'pending'\n * - all dependencies are 'completed'\n */\n getAvailable(): Task[] {\n const result: Task[] = [];\n for (const task of this.tasks.values()) {\n if (task.status !== 'pending') continue;\n\n const depsReady = task.deps.every(depId => {\n const dep = this.tasks.get(depId);\n return dep && dep.status === 'completed';\n });\n\n if (depsReady) {\n result.push({ ...task });\n }\n }\n return result;\n }\n\n /**\n * Get a single task by ID.\n */\n getTask(taskId: string): Task | null {\n const task = this.tasks.get(taskId);\n return task ? { ...task } : null;\n }\n\n /**\n * Check if a task's assignee matches the given agentId.\n */\n isAssignee(taskId: string, agentId: string): boolean {\n const task = this.tasks.get(taskId);\n return task?.assignee === agentId;\n }\n\n /** Serialize state for file persistence */\n serialize(): { tasks: Record<string, unknown> } {\n const tasks: Record<string, unknown> = {};\n for (const [id, t] of this.tasks) {\n tasks[id] = {\n ...t,\n createdAt: t.createdAt.toISOString(),\n updatedAt: t.updatedAt.toISOString(),\n };\n }\n return { tasks };\n }\n\n /** Hydrate state from file persistence */\n hydrate(data: { tasks?: Record<string, any> }): void {\n this.tasks.clear();\n if (!data?.tasks) return;\n for (const [id, raw] of Object.entries(data.tasks)) {\n this.tasks.set(id, {\n ...(raw as any),\n createdAt: new Date((raw as any).createdAt),\n updatedAt: new Date((raw as any).updatedAt),\n });\n }\n }\n}\n","/**\n * Team State Persistence — File-based shared state for cross-IDE team collaboration\n *\n * In stdio mode, each IDE spawns its own MCP process with isolated in-memory team state.\n * This persistence layer writes team state to a shared JSON file so all MCP processes\n * (Windsurf, Cursor, Claude Code, Antigravity, etc.) see the same agents, messages,\n * locks, and tasks.\n *\n * sync() — reload from disk if file changed (mtime check)\n * flush() — atomic write to disk (write tmp + rename)\n */\n\nimport { readFile, writeFile, mkdir } from 'node:fs/promises';\nimport { statSync, renameSync, existsSync } from 'node:fs';\nimport { dirname } from 'node:path';\nimport type { AgentRegistry } from './registry.js';\nimport type { MessageBus } from './messages.js';\nimport type { TaskManager } from './tasks.js';\nimport type { FileLockRegistry } from './file-locks.js';\n\n// ─── Types ───────────────────────────────────────────────────────────\n\ninterface TeamStateSnapshot {\n version: 1;\n updatedAt: string;\n registry: ReturnType<AgentRegistry['serialize']>;\n messages: ReturnType<MessageBus['serialize']>;\n tasks: ReturnType<TaskManager['serialize']>;\n locks: ReturnType<FileLockRegistry['serialize']>;\n}\n\n// ─── Persistence ─────────────────────────────────────────────────────\n\nexport class TeamPersistence {\n private lastMtimeMs = 0;\n\n constructor(\n private filePath: string,\n private registry: AgentRegistry,\n private messageBus: MessageBus,\n private taskManager: TaskManager,\n private fileLocks: FileLockRegistry,\n ) {}\n\n /** Reload state from disk if the file changed since last read */\n async sync(): Promise<void> {\n try {\n if (!existsSync(this.filePath)) return;\n const st = statSync(this.filePath);\n if (st.mtimeMs <= this.lastMtimeMs) return;\n } catch {\n return;\n }\n\n try {\n const raw = await readFile(this.filePath, 'utf8');\n const snap: TeamStateSnapshot = JSON.parse(raw);\n if (snap.version !== 1) return;\n\n this.registry.hydrate(snap.registry);\n this.messageBus.hydrate(snap.messages);\n this.taskManager.hydrate(snap.tasks);\n this.fileLocks.hydrate(snap.locks);\n\n try { this.lastMtimeMs = statSync(this.filePath).mtimeMs; } catch { /* */ }\n } catch {\n // Corrupted or partial write — ignore, will be overwritten on next flush\n }\n }\n\n /** Write current state to disk atomically (tmp + rename) */\n async flush(): Promise<void> {\n const snap: TeamStateSnapshot = {\n version: 1,\n updatedAt: new Date().toISOString(),\n registry: this.registry.serialize(),\n messages: this.messageBus.serialize(),\n tasks: this.taskManager.serialize(),\n locks: this.fileLocks.serialize(),\n };\n\n await mkdir(dirname(this.filePath), { recursive: true });\n const tmp = this.filePath + '.' + process.pid + '.tmp';\n await writeFile(tmp, JSON.stringify(snap, null, 2), 'utf8');\n\n try {\n renameSync(tmp, this.filePath);\n } catch {\n // Fallback: direct write if rename fails (cross-device)\n await writeFile(this.filePath, JSON.stringify(snap, null, 2), 'utf8');\n try { const { unlinkSync } = await import('node:fs'); unlinkSync(tmp); } catch { /* */ }\n }\n\n try { this.lastMtimeMs = statSync(this.filePath).mtimeMs; } catch { /* */ }\n }\n}\n","/**\n * Hook Installers\n *\n * Auto-detect installed agents and generate hook configurations.\n * Each agent has a different config format but the hook command is the same:\n * memorix hook\n *\n * The hook handler reads stdin JSON from the agent, normalizes it, and auto-stores.\n */\n\nimport * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport * as os from 'node:os';\n\nimport type { AgentName, AgentHookConfig } from '../types.js';\n\n/**\n * Resolve the hook command for the current platform.\n * On Windows, bare 'memorix' may resolve to a .ps1 script that non-PowerShell\n * environments can't execute. Using 'memorix.cmd' explicitly targets the CMD\n * shim that npm creates, which works in all shell environments and properly\n * forwards stdin (unlike 'cmd /c memorix' which can break stdin piping).\n */\nfunction resolveHookCommand(): string {\n if (process.platform === 'win32') {\n return 'memorix.cmd';\n }\n return 'memorix';\n}\n\n/**\n * Generate Claude Code hook config.\n * Format: .claude/settings.json\n * See: https://docs.anthropic.com/en/docs/claude-code/hooks\n */\nfunction generateClaudeConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n const hookEntry = {\n type: 'command',\n command: cmd,\n timeout: 10,\n };\n\n return {\n hooks: {\n SessionStart: [{ hooks: [hookEntry] }],\n PostToolUse: [{ hooks: [hookEntry] }],\n UserPromptSubmit: [{ hooks: [hookEntry] }],\n PreCompact: [{ hooks: [hookEntry] }],\n Stop: [{ hooks: [hookEntry] }],\n },\n };\n}\n\n/**\n * Generate GitHub Copilot hook config.\n * Format: .github/hooks/memorix.json — version:1 + bash/powershell fields\n * See: https://docs.github.com/en/copilot/reference/hooks-configuration\n */\nfunction generateCopilotConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n const hookEntry = {\n type: 'command',\n bash: cmd,\n powershell: cmd,\n timeoutSec: 10,\n };\n\n return {\n version: 1,\n hooks: {\n sessionStart: [hookEntry],\n sessionEnd: [hookEntry],\n userPromptSubmitted: [hookEntry],\n // NOTE: preToolUse intentionally omitted — VS Code Copilot requires\n // hookSpecificOutput.permissionDecision in the response; memorix is\n // an observer, not a gatekeeper, so we only use postToolUse.\n postToolUse: [hookEntry],\n errorOccurred: [hookEntry],\n },\n };\n}\n\n/**\n * Generate Gemini CLI / Antigravity hook config.\n * Format: .gemini/settings.json — PascalCase events, timeout in milliseconds\n * See: https://geminicli.com/docs/hooks/\n */\nfunction generateGeminiConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n\n // Gemini CLI hooks: defined in settings.json under \"hooks\" object.\n // Each event key (SessionStart, AfterTool, etc.) maps to an array of hook definitions.\n // No \"enabled\" flag needed — hooks are active simply by being defined.\n // See: https://geminicli.com/docs/hooks/reference/\n function entry(name: string, desc: string) {\n return {\n matcher: '*',\n hooks: [{ name, type: 'command', command: cmd, description: desc }],\n };\n }\n\n return {\n hooks: {\n SessionStart: [entry('memorix-session-start', 'Load memorix context at session start')],\n AfterTool: [entry('memorix-after-tool', 'Record tool usage in memorix')],\n AfterAgent: [entry('memorix-after-agent', 'Record agent response in memorix')],\n PreCompress: [entry('memorix-pre-compress', 'Save context before compression')],\n },\n };\n}\n\n/**\n * Generate Windsurf Cascade hooks config.\n */\nfunction generateWindsurfConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n const hookEntry = {\n command: cmd,\n show_output: false,\n };\n\n return {\n hooks: {\n post_write_code: [hookEntry],\n post_run_command: [hookEntry],\n post_mcp_tool_use: [hookEntry],\n pre_user_prompt: [hookEntry],\n post_cascade_response: [hookEntry],\n },\n };\n}\n\n/**\n * Generate Cursor hooks config.\n */\nfunction generateCursorConfig(): Record<string, unknown> {\n const cmd = `${resolveHookCommand()} hook`;\n // Cursor hooks format: version (number) + each event is an array of hook scripts\n // See: https://cursor.com/docs/agent/hooks\n const hookScript = { command: cmd };\n return {\n version: 1,\n hooks: {\n sessionStart: [hookScript],\n beforeSubmitPrompt: [hookScript],\n afterFileEdit: [hookScript],\n beforeShellExecution: [hookScript],\n afterMCPExecution: [hookScript],\n preCompact: [hookScript],\n stop: [hookScript],\n },\n };\n}\n\n/**\n * Generate Kiro hook files.\n * Format: .kiro/hooks/*.kiro.hook — JSON config\n * See: https://kiro.dev/docs/hooks/\n * Schema confirmed from: github.com/awsdataarchitect/kiro-best-practices\n */\nfunction generateKiroHookFiles(): Array<{ filename: string; content: string }> {\n const cmd = `${resolveHookCommand()} hook`;\n return [\n {\n filename: 'memorix-agent-stop.kiro.hook',\n content: JSON.stringify({\n enabled: true,\n name: 'Memorix Session Memory',\n description: 'Record session context when agent completes a turn',\n version: '1',\n when: { type: 'agentStop' },\n then: {\n type: 'askAgent',\n prompt: 'Call memorix MCP tools to store important context from this conversation:\\n1. Use memorix_store to record any decisions, bug fixes, gotchas, or configuration changes\\n2. Include relevant file paths and concepts for searchability',\n },\n }, null, 2),\n },\n {\n filename: 'memorix-prompt-submit.kiro.hook',\n content: JSON.stringify({\n enabled: true,\n name: 'Memorix Context Loader',\n description: 'Load relevant memories when user submits a prompt',\n version: '1',\n when: { type: 'promptSubmit' },\n then: {\n type: 'askAgent',\n prompt: 'Before responding, load context:\\n1. Call memorix_session_start to get previous session summary and key memories\\n2. Call memorix_search with a query related to the user\\'s prompt for additional context\\n3. If search results are found, use memorix_detail to fetch the most relevant ones\\n4. Reference relevant memories naturally in your response',\n },\n }, null, 2),\n },\n {\n filename: 'memorix-file-save.kiro.hook',\n content: JSON.stringify({\n enabled: true,\n name: 'Memorix File Change Tracker',\n description: 'Track significant file changes for cross-session memory',\n version: '1',\n when: {\n type: 'fileEdited',\n patterns: ['**/*.ts', '**/*.js', '**/*.tsx', '**/*.jsx', '**/*.py', '**/*.rs', '**/*.go', '**/*.java', '**/*.md'],\n },\n then: {\n type: 'runCommand',\n command: cmd,\n },\n }, null, 2),\n },\n ];\n}\n\n/**\n * Generate OpenCode plugin file content.\n * Format: .opencode/plugins/memorix.js — Bun-compatible JS module\n * See: https://opencode.ai/docs/plugins/\n *\n * The plugin hooks into OpenCode events and pipes JSON to `memorix hook`\n * via Bun.spawn, matching the same stdin/stdout protocol used by all agents.\n */\nfunction generateOpenCodePlugin(): string {\n return `/**\n * Memorix — Cross-Agent Memory Bridge Plugin for OpenCode\n *\n * Automatically captures session context and tool usage,\n * piping events to \\`memorix hook\\` for cross-agent memory persistence.\n *\n * Generated by: memorix installHooks('opencode', projectRoot)\n * Docs: https://github.com/AVIDS2/memorix\n */\nexport const MemorixPlugin = async ({ project, client, $, directory, worktree }) => {\n // Generate a stable session ID for this plugin lifetime\n const sessionId = \\`opencode-\\${Date.now().toString(36)}-\\${Math.random().toString(36).slice(2, 8)}\\`;\n\n /** Pipe event JSON to memorix hook via temp file (Windows .cmd stdin workaround) */\n async function runHook(payload) {\n payload.session_id = sessionId;\n const tmpDir = Bun.env.TEMP || Bun.env.TMP || '/tmp';\n const tmpPath = \\`\\${tmpDir}/memorix-hook-\\${Date.now()}.json\\`;\n try {\n const data = JSON.stringify(payload);\n await Bun.write(tmpPath, data);\n // cat | pipe works through .cmd wrappers; < redirect does NOT\n await $\\`cat \\${tmpPath} | memorix hook\\`.quiet().nothrow();\n } catch {\n // Silent — hooks must never break the agent\n } finally {\n try { const { unlinkSync } = await import('node:fs'); unlinkSync(tmpPath); } catch {}\n }\n }\n\n return {\n /** Catch-all event handler for session lifecycle + file events */\n event: async ({ event }) => {\n if (event.type === 'session.created') {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'session.created',\n cwd: directory,\n });\n } else if (event.type === 'session.idle') {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'session.idle',\n cwd: directory,\n });\n } else if (event.type === 'file.edited') {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'file.edited',\n file_path: event.properties?.path ?? '',\n cwd: directory,\n });\n } else if (event.type === 'command.executed') {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'command.executed',\n command: event.properties?.command ?? '',\n cwd: directory,\n });\n }\n },\n\n /** Record tool usage after execution (hook, not event) */\n 'tool.execute.after': async (input, output) => {\n await runHook({\n agent: 'opencode',\n hook_event_name: 'tool.execute.after',\n tool_name: input.tool,\n tool_input: input.args,\n cwd: directory,\n });\n },\n\n /** Inject memorix context into compaction prompt */\n 'experimental.session.compacting': async (input, output) => {\n output.context.push(\n '## Memorix Cross-Agent Memory\\\\n' +\n 'Before compacting, use memorix_store to save important discoveries, decisions, and gotchas.\\\\n' +\n 'After compacting, use memorix_session_start to reload session context, then memorix_search for specific topics.'\n );\n },\n };\n};\n`;\n}\n\n/**\n * Get the config file path for an agent (project-level).\n */\nfunction getProjectConfigPath(agent: AgentName, projectRoot: string): string {\n switch (agent) {\n case 'claude':\n // Claude Code reads hooks from .claude/settings.local.json (project-level, gitignored)\n return path.join(projectRoot, '.claude', 'settings.local.json');\n case 'copilot':\n return path.join(projectRoot, '.github', 'hooks', 'memorix.json');\n case 'windsurf':\n return path.join(projectRoot, '.windsurf', 'hooks.json');\n case 'cursor':\n return path.join(projectRoot, '.cursor', 'hooks.json');\n case 'kiro':\n return path.join(projectRoot, '.kiro', 'hooks', 'memorix-agent-stop.kiro.hook');\n case 'codex':\n // Codex has no hooks system — only rules (AGENTS.md)\n return path.join(projectRoot, 'AGENTS.md');\n case 'trae':\n // Trae has no hooks system — only rules (.trae/rules/project_rules.md)\n return path.join(projectRoot, '.trae', 'rules', 'project_rules.md');\n case 'opencode':\n // OpenCode uses plugin files for hooks\n return path.join(projectRoot, '.opencode', 'plugins', 'memorix.js');\n case 'antigravity':\n return path.join(projectRoot, '.gemini', 'settings.json');\n default:\n return path.join(projectRoot, '.memorix', 'hooks.json');\n }\n}\n\n/**\n * Get the global config file path for an agent.\n */\nfunction getGlobalConfigPath(agent: AgentName): string {\n const home = os.homedir();\n switch (agent) {\n case 'claude':\n case 'copilot':\n return path.join(home, '.claude', 'settings.json');\n case 'windsurf':\n return path.join(home, '.codeium', 'windsurf', 'hooks.json');\n case 'cursor':\n return path.join(home, '.cursor', 'hooks.json');\n case 'antigravity':\n return path.join(home, '.gemini', 'settings.json');\n case 'opencode':\n return path.join(home, '.config', 'opencode', 'plugins', 'memorix.js');\n case 'trae':\n return path.join(home, '.trae', 'rules', 'project_rules.md');\n default:\n return path.join(home, '.memorix', 'hooks.json');\n }\n}\n\n/**\n * Detect which agents are installed on the system.\n */\nexport async function detectInstalledAgents(): Promise<AgentName[]> {\n const agents: AgentName[] = [];\n const home = os.homedir();\n\n // Check for Claude Code\n const claudeDir = path.join(home, '.claude');\n try {\n await fs.access(claudeDir);\n agents.push('claude');\n } catch { /* not installed */ }\n\n // Check for Windsurf\n const windsurfDir = path.join(home, '.codeium', 'windsurf');\n try {\n await fs.access(windsurfDir);\n agents.push('windsurf');\n } catch { /* not installed */ }\n\n // Check for Cursor\n const cursorDir = path.join(home, '.cursor');\n try {\n await fs.access(cursorDir);\n agents.push('cursor');\n } catch { /* not installed */ }\n\n // Check for VS Code Copilot (independent of Claude Code — different hook paths)\n const vscodeDir = path.join(home, '.vscode');\n try {\n await fs.access(vscodeDir);\n agents.push('copilot');\n } catch { /* not installed */ }\n\n // Check for Kiro\n const kiroConfig = path.join(home, '.kiro');\n try {\n await fs.access(kiroConfig);\n agents.push('kiro');\n } catch { /* not installed */ }\n\n // Check for Codex\n const codexDir = path.join(home, '.codex');\n try {\n await fs.access(codexDir);\n agents.push('codex');\n } catch { /* not installed */ }\n\n // Check for Antigravity / Gemini CLI (both share ~/.gemini/)\n const geminiDir = path.join(home, '.gemini');\n try {\n await fs.access(geminiDir);\n agents.push('antigravity');\n } catch { /* not installed */ }\n\n // Check for OpenCode\n const opencodeDir = path.join(home, '.config', 'opencode');\n try {\n await fs.access(opencodeDir);\n agents.push('opencode');\n } catch { /* not installed */ }\n\n // Check for Trae\n const traeDir = path.join(home, '.trae');\n try {\n await fs.access(traeDir);\n agents.push('trae');\n } catch { /* not installed */ }\n\n return agents;\n}\n\n/**\n * Install hooks for a specific agent.\n */\nexport async function installHooks(\n agent: AgentName,\n projectRoot: string,\n global = false,\n): Promise<AgentHookConfig> {\n const configPath = global\n ? getGlobalConfigPath(agent)\n : getProjectConfigPath(agent, projectRoot);\n\n let generated: Record<string, unknown> | string;\n\n switch (agent) {\n case 'claude':\n generated = generateClaudeConfig();\n break;\n case 'copilot':\n generated = generateCopilotConfig();\n break;\n case 'windsurf':\n generated = generateWindsurfConfig();\n break;\n case 'cursor':\n generated = generateCursorConfig();\n break;\n case 'antigravity':\n generated = generateGeminiConfig();\n break;\n case 'kiro':\n generated = 'kiro-multi'; // handled separately below\n break;\n case 'codex':\n // Codex has no hooks — only install rules\n await installAgentRules(agent, projectRoot);\n return {\n agent,\n configPath: getProjectConfigPath(agent, projectRoot),\n events: [],\n generated: { note: 'Codex has no hooks system, only rules (AGENTS.md) installed' },\n };\n case 'trae':\n // Trae has no hooks system — only install rules\n await installAgentRules(agent, projectRoot);\n return {\n agent,\n configPath: getProjectConfigPath(agent, projectRoot),\n events: [],\n generated: { note: 'Trae has no hooks system, only rules (.trae/rules/project_rules.md) installed' },\n };\n case 'opencode': {\n // OpenCode uses JS plugin files for hooks\n const pluginContent = generateOpenCodePlugin();\n const pluginPath = global\n ? getGlobalConfigPath(agent)\n : getProjectConfigPath(agent, projectRoot);\n await fs.mkdir(path.dirname(pluginPath), { recursive: true });\n await fs.writeFile(pluginPath, pluginContent, 'utf-8');\n await installAgentRules(agent, projectRoot);\n return {\n agent,\n configPath: pluginPath,\n events: ['session_start', 'session_end', 'post_tool', 'post_edit', 'pre_compact'],\n generated: { note: 'OpenCode plugin installed at ' + pluginPath },\n };\n }\n default:\n generated = generateClaudeConfig(); // fallback\n }\n\n // Ensure directory exists\n await fs.mkdir(path.dirname(configPath), { recursive: true });\n\n if (agent === 'kiro') {\n // Kiro uses multiple .kiro.hook files\n const hookFiles = generateKiroHookFiles();\n const hooksDir = path.join(path.dirname(configPath));\n await fs.mkdir(hooksDir, { recursive: true });\n for (const hf of hookFiles) {\n await fs.writeFile(path.join(hooksDir, hf.filename), hf.content, 'utf-8');\n }\n } else {\n // JSON-based configs: merge with existing if present\n let existing: Record<string, unknown> = {};\n try {\n const content = await fs.readFile(configPath, 'utf-8');\n existing = JSON.parse(content);\n } catch { /* file doesn't exist yet */ }\n\n // Deep-merge generated keys so we don't overwrite user's existing config\n const gen = generated as Record<string, unknown>;\n const merged = { ...existing };\n\n // CRITICAL: version must be a number (Cursor requires this)\n // Always use generated version to fix corrupted configs\n if (typeof gen.version === 'number') {\n merged.version = gen.version;\n } else if (typeof merged.version !== 'number') {\n // Fallback: ensure version is always a number\n merged.version = 1;\n }\n\n // Merge 'hooks' key (all agents)\n if (gen.hooks && typeof gen.hooks === 'object') {\n const existingHooks = (existing.hooks && typeof existing.hooks === 'object')\n ? existing.hooks as Record<string, unknown>\n : {};\n merged.hooks = { ...existingHooks, ...(gen.hooks as Record<string, unknown>) };\n }\n\n // Merge 'tools' key (preserve any user-defined tools config)\n if (gen.tools && typeof gen.tools === 'object') {\n const existingTools = (existing.tools && typeof existing.tools === 'object')\n ? existing.tools as Record<string, unknown>\n : {};\n merged.tools = { ...existingTools, ...(gen.tools as Record<string, unknown>) };\n }\n\n // Clean up stale keys from older memorix versions\n if (agent === 'antigravity') {\n const h = merged.hooks as Record<string, unknown> | undefined;\n if (h && typeof h.enabled === 'boolean') delete h.enabled;\n const t = merged.tools as Record<string, unknown> | undefined;\n if (t) {\n delete t.enableHooks;\n if (Object.keys(t).length === 0) delete merged.tools;\n }\n }\n if (agent === 'copilot') {\n // Remove preToolUse — VS Code Copilot requires hookSpecificOutput\n // in response which memorix doesn't provide (observer, not gatekeeper)\n const h = merged.hooks as Record<string, unknown> | undefined;\n if (h) delete h.preToolUse;\n }\n\n await fs.writeFile(configPath, JSON.stringify(merged, null, 2), 'utf-8');\n }\n\n const events: Array<import('../types.js').HookEvent> = [];\n switch (agent) {\n case 'claude':\n events.push('session_start', 'post_tool', 'user_prompt', 'pre_compact', 'session_end');\n break;\n case 'copilot':\n events.push('session_start', 'session_end', 'user_prompt', 'post_tool');\n break;\n case 'windsurf':\n events.push('post_edit', 'post_command', 'post_tool', 'user_prompt', 'post_response');\n break;\n case 'cursor':\n events.push('session_start', 'user_prompt', 'post_edit', 'post_tool', 'pre_compact', 'session_end');\n break;\n case 'antigravity':\n events.push('session_start', 'post_tool', 'post_response', 'pre_compact');\n break;\n case 'kiro':\n events.push('session_end', 'user_prompt', 'post_edit');\n break;\n }\n\n // Install agent rules alongside hooks\n await installAgentRules(agent, projectRoot);\n\n return {\n agent,\n configPath,\n events,\n generated: typeof generated === 'string' ? { content: generated } : generated,\n };\n}\n\n/**\n * Install memorix agent rules for a specific agent.\n * Rules instruct the agent to proactively use memorix for context continuity.\n */\nasync function installAgentRules(agent: AgentName, projectRoot: string): Promise<void> {\n const rulesContent = getAgentRulesContent(agent);\n let rulesPath: string;\n\n switch (agent) {\n case 'windsurf':\n rulesPath = path.join(projectRoot, '.windsurf', 'rules', 'memorix.md');\n break;\n case 'cursor':\n rulesPath = path.join(projectRoot, '.cursor', 'rules', 'memorix.mdc');\n break;\n case 'claude':\n case 'copilot':\n rulesPath = path.join(projectRoot, '.github', 'copilot-instructions.md');\n break;\n case 'codex':\n rulesPath = path.join(projectRoot, 'AGENTS.md');\n break;\n case 'kiro':\n rulesPath = path.join(projectRoot, '.kiro', 'steering', 'memorix.md');\n break;\n case 'opencode':\n // OpenCode reads AGENTS.md (same as Codex), also supports CLAUDE.md as fallback\n rulesPath = path.join(projectRoot, 'AGENTS.md');\n break;\n case 'antigravity':\n // Gemini CLI reads context from GEMINI.md by default (like Codex reads AGENTS.md)\n // See: context.fileName defaults to [\"GEMINI.md\", \"CONTEXT.md\"]\n rulesPath = path.join(projectRoot, 'GEMINI.md');\n break;\n case 'trae':\n rulesPath = path.join(projectRoot, '.trae', 'rules', 'project_rules.md');\n break;\n default:\n rulesPath = path.join(projectRoot, '.agent', 'rules', 'memorix.md');\n break;\n }\n\n try {\n await fs.mkdir(path.dirname(rulesPath), { recursive: true });\n\n if (agent === 'codex' || agent === 'opencode' || agent === 'antigravity') {\n // For shared context files (AGENTS.md / GEMINI.md), append rather than overwrite\n try {\n const existing = await fs.readFile(rulesPath, 'utf-8');\n if (existing.includes('Memorix')) {\n return; // Already contains memorix rules\n }\n // Append to existing file\n await fs.writeFile(rulesPath, existing + '\\n\\n' + rulesContent, 'utf-8');\n } catch {\n // File doesn't exist, create it\n await fs.writeFile(rulesPath, rulesContent, 'utf-8');\n }\n } else {\n // Only write if not already present\n try {\n await fs.access(rulesPath);\n // File exists — don't overwrite user customizations\n } catch {\n await fs.writeFile(rulesPath, rulesContent, 'utf-8');\n }\n }\n } catch { /* silent */ }\n}\n\n/**\n * Get the memorix agent rules content.\n * Windsurf requires YAML frontmatter with trigger mode.\n * Cursor .mdc files use a similar frontmatter format.\n */\nfunction getAgentRulesContent(agent?: AgentName): string {\n let frontmatter = '';\n if (agent === 'windsurf') {\n frontmatter = `---\ntrigger: always_on\n---\n\n`;\n } else if (agent === 'cursor') {\n frontmatter = `---\ndescription: Memorix automatic memory recording rules\nalwaysApply: true\n---\n\n`;\n }\n return `${frontmatter}# Memorix — Automatic Memory Rules\n\nYou have access to Memorix memory tools. Follow these rules to maintain persistent context across sessions.\n\n## RULE 1: Session Start — Load Context\n\nAt the **beginning of every conversation**, BEFORE responding to the user:\n\n1. Call \\`memorix_session_start\\` to get the previous session summary and key memories (this is a direct read, not a search — no fragmentation risk)\n2. Then call \\`memorix_search\\` with a query related to the user's first message for additional context\n3. If search results are found, use \\`memorix_detail\\` to fetch the most relevant ones\n4. Reference relevant memories naturally — the user should feel you \"remember\" them\n\n## RULE 2: Store Important Context\n\n**Proactively** call \\`memorix_store\\` when any of the following happen:\n\n### What MUST be recorded:\n- Architecture/design decisions → type: \\`decision\\`\n- Bug identified and fixed → type: \\`problem-solution\\`\n- Unexpected behavior or gotcha → type: \\`gotcha\\`\n- Config changed (env vars, ports, deps) → type: \\`what-changed\\`\n- Feature completed or milestone → type: \\`what-changed\\`\n- Trade-off discussed with conclusion → type: \\`trade-off\\`\n\n### What should NOT be recorded:\n- Simple file reads, greetings, trivial commands (ls, pwd, git status)\n\n### Use topicKey for evolving topics:\nFor decisions, architecture docs, or any topic that evolves over time, ALWAYS use \\`topicKey\\` parameter.\nThis ensures the memory is UPDATED instead of creating duplicates.\nUse \\`memorix_suggest_topic_key\\` to generate a stable key.\n\nExample: \\`topicKey: \"architecture/auth-model\"\\` — subsequent stores with the same key update the existing memory.\n\n### Track progress with the progress parameter:\nWhen working on features or tasks, include the \\`progress\\` parameter:\n\\`\\`\\`json\n{\n \"progress\": {\n \"feature\": \"user authentication\",\n \"status\": \"in-progress\",\n \"completion\": 60\n }\n}\n\\`\\`\\`\nStatus values: \\`in-progress\\`, \\`completed\\`, \\`blocked\\`\n\n## RULE 3: Resolve Completed Memories\n\nWhen a task is completed, a bug is fixed, or information becomes outdated:\n\n1. Call \\`memorix_resolve\\` with the observation IDs to mark them as resolved\n2. Resolved memories are hidden from default search, preventing context pollution\n\nThis is critical — without resolving, old bug reports and completed tasks will keep appearing in future searches.\n\n## RULE 4: Session End — Store Decision Chain Summary\n\nWhen the conversation is ending, create a **decision chain summary** (not just a checklist):\n\n1. Call \\`memorix_store\\` with type \\`session-request\\` and \\`topicKey: \"session/latest-summary\"\\`:\n\n **Required structure:**\n \\`\\`\\`\n ## Goal\n [What we were working on — specific, not vague]\n\n ## Key Decisions & Reasoning\n - Chose X because Y. Rejected Z because [reason].\n - [Every architectural/design decision with WHY]\n\n ## What Changed\n - [File path] — [what changed and why]\n\n ## Current State\n - [What works now, what's pending]\n - [Any blockers or risks]\n\n ## Next Steps\n - [Concrete next actions, in priority order]\n \\`\\`\\`\n\n **Critical: Include the \"Key Decisions & Reasoning\" section.** Without it, the next AI session will lack the context to understand WHY things were done a certain way and may suggest conflicting approaches.\n\n2. Call \\`memorix_resolve\\` on any memories for tasks completed in this session\n\n## RULE 5: Compact Awareness\n\nMemorix automatically compacts memories on store:\n- **With LLM API configured:** Smart dedup — extracts facts, compares with existing, merges or skips duplicates\n- **Without LLM (free mode):** Heuristic dedup — uses similarity scores to detect and merge duplicate memories\n- **You don't need to manually deduplicate.** Just store naturally and compact handles the rest.\n- If you notice excessive duplicate memories, call \\`memorix_deduplicate\\` for batch cleanup.\n\n## Guidelines\n\n- **Use concise titles** (~5-10 words) and structured facts\n- **Include file paths** in filesModified when relevant\n- **Include related concepts** for better searchability\n- **Always use topicKey** for recurring topics to prevent duplicates\n- **Always resolve** completed tasks and fixed bugs\n- **Always include reasoning** — \"chose X because Y\" is 10x more valuable than \"did X\"\n- Search defaults to \\`status=\"active\"\\` — use \\`status=\"all\"\\` to include resolved memories\n`;\n}\n\n/**\n * Uninstall hooks for a specific agent.\n */\nexport async function uninstallHooks(\n agent: AgentName,\n projectRoot: string,\n global = false,\n): Promise<boolean> {\n const configPath = global\n ? getGlobalConfigPath(agent)\n : getProjectConfigPath(agent, projectRoot);\n\n try {\n if (agent === 'kiro') {\n await fs.unlink(configPath);\n } else {\n // For JSON configs, remove the hooks key\n const content = await fs.readFile(configPath, 'utf-8');\n const config = JSON.parse(content);\n delete config.hooks;\n\n if (Object.keys(config).length === 0) {\n await fs.unlink(configPath);\n } else {\n await fs.writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');\n }\n }\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check hook installation status for all agents.\n */\nexport async function getHookStatus(\n projectRoot: string,\n): Promise<Array<{ agent: AgentName; installed: boolean; configPath: string }>> {\n const results: Array<{ agent: AgentName; installed: boolean; configPath: string }> = [];\n const agents: AgentName[] = ['claude', 'copilot', 'windsurf', 'cursor', 'kiro', 'codex', 'antigravity', 'opencode', 'trae'];\n\n for (const agent of agents) {\n const projectPath = getProjectConfigPath(agent, projectRoot);\n const globalPath = getGlobalConfigPath(agent);\n\n let installed = false;\n let usedPath = projectPath;\n\n try {\n await fs.access(projectPath);\n installed = true;\n } catch {\n try {\n await fs.access(globalPath);\n installed = true;\n usedPath = globalPath;\n } catch { /* not installed */ }\n }\n\n results.push({ agent, installed, configPath: usedPath });\n }\n\n return results;\n}\n","#!/usr/bin/env node\n\n/**\n * Memorix — Cross-Agent Memory Bridge\n *\n * Entry point for the MCP Server.\n * Connects via stdio transport for compatibility with all MCP-supporting agents.\n *\n * Usage:\n * node dist/index.js # Start as MCP server (stdio)\n * memorix init # CLI: Initialize project (P1)\n * memorix sync # CLI: Sync rules across agents (P2)\n */\n\nimport { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';\nimport { createMemorixServer } from './server.js';\n\nasync function main(): Promise<void> {\n const { server, projectId, deferredInit } = await createMemorixServer();\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n console.error(`[memorix] MCP Server running on stdio (project: ${projectId})`);\n deferredInit().catch(e => console.error(`[memorix] Deferred init error:`, e));\n}\n\nmain().catch((error) => {\n console.error('[memorix] Fatal error:', error);\n process.exit(1);\n});\n","/**\n * Memorix MCP Server\n *\n * Registers all MCP tools and handles the server lifecycle.\n *\n * Tool sources:\n * - memorix_store / memorix_search / memorix_detail / memorix_timeline:\n * Memorix extensions using claude-mem's 3-layer Progressive Disclosure\n * - create_entities / create_relations / add_observations / delete_entities /\n * delete_observations / delete_relations / search_nodes / open_nodes / read_graph:\n * MCP Official Memory Server compatible interface (P1)\n *\n * Extensibility:\n * - New tools can be registered via server.registerTool()\n * - Rules sync tools will be added in P2\n * - New agent format adapters plug in without changing this file\n */\n\nimport { watchFile } from 'node:fs';\nimport { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';\nimport { z } from 'zod';\nimport { KnowledgeGraphManager } from './memory/graph.js';\nimport { initObservations, storeObservation, reindexObservations, migrateProjectIds, getObservation } from './memory/observations.js';\nimport { resetDb } from './store/orama-store.js';\nimport { createAutoRelations } from './memory/auto-relations.js';\nimport { extractEntities } from './memory/entity-extractor.js';\nimport { compactSearch, compactTimeline, compactDetail } from './compact/engine.js';\nimport { detectProject } from './project/detector.js';\nimport { registerAlias, initAliasRegistry, resolveAliases, autoMergeByBaseName } from './project/aliases.js';\nimport { getProjectDataDir } from './store/persistence.js';\nimport type { ObservationType, RuleSource, AgentTarget, MCPServerEntry } from './types.js';\nimport { RulesSyncer } from './rules/syncer.js';\nimport { WorkspaceSyncEngine } from './workspace/engine.js';\nimport { initLLM, isLLMEnabled, getLLMConfig } from './llm/provider.js';\nimport { compactOnWrite, deduplicateMemory } from './llm/memory-manager.js';\nimport type { ExistingMemory } from './llm/memory-manager.js';\n\n/** Timestamp of last MCP-initiated write — hot-reload skips changes within 10s */\nlet lastInternalWriteMs = 0;\nconst markInternalWrite = () => { lastInternalWriteMs = Date.now(); };\n\n/** Valid observation types for input validation */\nconst OBSERVATION_TYPES: [string, ...string[]] = [\n 'session-request',\n 'gotcha',\n 'problem-solution',\n 'how-it-works',\n 'what-changed',\n 'discovery',\n 'why-it-exists',\n 'decision',\n 'trade-off',\n];\n\n/**\n * Defensive parameter coercion for Claude Code CLI + non-Anthropic models (e.g. GLM).\n * Claude Code CLI has a known bug (#5504, #26027) where JSON objects/arrays\n * get serialized as strings. GLM models amplify this by producing string-encoded\n * arrays/numbers in tool calls. These helpers ensure Memorix works regardless.\n */\nfunction coerceNumberArray(val: unknown): number[] {\n if (Array.isArray(val)) return val.map(Number);\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (Array.isArray(parsed)) return parsed.map(Number);\n } catch { /* not valid JSON */ }\n }\n return [];\n}\n\nfunction coerceNumber(val: unknown, fallback: number): number {\n if (typeof val === 'number') return val;\n if (typeof val === 'string') {\n const n = Number(val);\n if (!Number.isNaN(n)) return n;\n }\n return fallback;\n}\n\nfunction coerceStringArray(val: unknown): string[] {\n if (Array.isArray(val)) return val.map(String);\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (Array.isArray(parsed)) return parsed.map(String);\n } catch { /* not valid JSON */ }\n }\n return [];\n}\n\nfunction coerceObject<T>(val: unknown): T | null {\n if (typeof val === 'object' && val !== null && !Array.isArray(val)) return val as T;\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (typeof parsed === 'object' && parsed !== null) return parsed as T;\n } catch { /* not valid JSON */ }\n }\n return null;\n}\n\nfunction coerceObjectArray<T>(val: unknown): T[] {\n if (Array.isArray(val)) {\n return val.map(item => {\n if (typeof item === 'string') {\n try { return JSON.parse(item); } catch { return item; }\n }\n return item;\n });\n }\n if (typeof val === 'string') {\n try {\n const parsed = JSON.parse(val);\n if (Array.isArray(parsed)) return parsed;\n } catch { /* not valid JSON */ }\n }\n return [];\n}\n\n/**\n * Create and configure the Memorix MCP Server.\n */\n/** Optional shared team instances — passed by serve-http so all sessions share state */\nexport interface SharedTeamInstances {\n registry: InstanceType<typeof import('./team/registry.js').AgentRegistry>;\n messageBus: InstanceType<typeof import('./team/messages.js').MessageBus>;\n fileLocks: InstanceType<typeof import('./team/file-locks.js').FileLockRegistry>;\n taskManager: InstanceType<typeof import('./team/tasks.js').TaskManager>;\n}\n\nexport async function createMemorixServer(cwd?: string, existingServer?: McpServer, sharedTeam?: SharedTeamInstances): Promise<{\n server: McpServer;\n graphManager: KnowledgeGraphManager;\n projectId: string;\n deferredInit: () => Promise<void>;\n}> {\n // Detect current project (never returns __invalid__ — degraded mode uses placeholder/)\n const rawProject = detectProject(cwd);\n\n // Migrate legacy per-project subdirectories into flat base directory (one-time, silent)\n try {\n const { migrateSubdirsToFlat } = await import('./store/persistence.js');\n const migrated = await migrateSubdirsToFlat();\n if (migrated) {\n console.error(`[memorix] Migrated per-project subdirectories into flat storage`);\n }\n } catch { /* migration is optional */ }\n\n const projectDir = await getProjectDataDir(rawProject.id);\n\n // Register alias and resolve to canonical project ID.\n // This ensures the same physical project always uses the same ID\n // regardless of which IDE or detection method discovered it.\n initAliasRegistry(projectDir);\n const canonicalId = await registerAlias(rawProject);\n const project = { ...rawProject, id: canonicalId };\n if (canonicalId !== rawProject.id) {\n console.error(`[memorix] Alias resolved: ${rawProject.id} → ${canonicalId}`);\n }\n\n // Initialize components\n const graphManager = new KnowledgeGraphManager(projectDir);\n await graphManager.init();\n await initObservations(projectDir);\n\n // Auto-merge obvious alias groups by scanning observed projectIds in data.\n // This detects splits like placeholder/foo + local/foo + user/foo\n try {\n const { getAllObservations } = await import('./memory/observations.js');\n const allObs = getAllObservations();\n const observedIds = [...new Set(allObs.map(o => o.projectId))];\n const merged = await autoMergeByBaseName(observedIds);\n if (merged > 0) {\n console.error(`[memorix] Auto-merged ${merged} alias group(s) by base name`);\n }\n } catch { /* auto-merge is optional */ }\n\n // Migrate existing observations to canonical project ID for ALL alias groups.\n // This normalizes split projectIds like placeholder/foo + local/foo → canonical.\n try {\n const { getAllAliasGroups } = await import('./project/aliases.js');\n const groups = await getAllAliasGroups();\n let totalMigrated = 0;\n for (const group of groups) {\n if (group.aliases.length > 1) {\n const migrated = await migrateProjectIds(group.aliases, group.canonical);\n if (migrated > 0) {\n console.error(`[memorix] Migrated ${migrated} observations → ${group.canonical}`);\n totalMigrated += migrated;\n }\n }\n }\n if (totalMigrated > 0) {\n console.error(`[memorix] Total migrated: ${totalMigrated} observations across ${groups.filter(g => g.aliases.length > 1).length} project(s)`);\n }\n } catch { /* migration is optional */ }\n\n // Reindex existing observations into Orama\n const reindexed = await reindexObservations();\n if (reindexed > 0) {\n console.error(`[memorix] Reindexed ${reindexed} observations for project: ${project.id}`);\n }\n\n // Initialize LLM provider (optional — graceful degradation)\n const llmConfig = initLLM();\n if (llmConfig) {\n console.error(`[memorix] LLM enhanced mode: ${llmConfig.provider}/${llmConfig.model}`);\n } else {\n console.error(`[memorix] LLM mode: off (set MEMORIX_LLM_API_KEY or OPENAI_API_KEY to enable)`);\n }\n\n console.error(`[memorix] Project: ${project.id} (${project.name})`);\n console.error(`[memorix] Data dir: ${projectDir}`);\n\n // Sync advisory variables — populated by deferredInit(), used by memorix_search\n let syncAdvisoryShown = false;\n let syncAdvisory: string | null = null;\n\n // Create MCP server (or use existing one from roots-aware flow)\n const server = existingServer ?? new McpServer({\n name: 'memorix',\n version: typeof __MEMORIX_VERSION__ !== 'undefined' ? __MEMORIX_VERSION__ : '1.0.1',\n });\n\n // ================================================================\n // Memorix Extended Tools (3-layer Progressive Disclosure)\n // ================================================================\n\n /**\n * memorix_store — Store a new observation\n *\n * Primary write API. Agents call this to persist knowledge.\n * Auto-assigns ID, counts tokens, indexes for search.\n */\n server.registerTool(\n 'memorix_store',\n {\n title: 'Store Memory',\n description:\n 'Store a new observation/memory. Automatically indexed for search. ' +\n 'Use type to classify: gotcha (🔴 critical pitfall), decision (🟤 architecture choice), ' +\n 'problem-solution (🟡 bug fix), how-it-works (🔵 explanation), what-changed (🟢 change), ' +\n 'discovery (🟣 insight), why-it-exists (🟠 rationale), trade-off (⚖️ compromise), ' +\n 'session-request (🎯 original goal). ' +\n 'Stored memories persist across sessions and are shared with other IDEs (Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, Trae) via the same local data directory.',\n inputSchema: {\n entityName: z.string().describe('The entity this observation belongs to (e.g., \"auth-module\", \"port-config\")'),\n type: z.enum(OBSERVATION_TYPES).describe('Observation type for classification'),\n title: z.string().describe('Short descriptive title (~5-10 words)'),\n narrative: z.string().describe('Full description of the observation'),\n facts: z.array(z.string()).optional().describe('Structured facts (e.g., \"Default timeout: 60s\")'),\n filesModified: z.array(z.string()).optional().describe('Files involved'),\n concepts: z.array(z.string()).optional().describe('Related concepts/keywords'),\n topicKey: z.string().optional().describe(\n 'Optional topic identifier for upserts (e.g., \"architecture/auth-model\"). ' +\n 'If an observation with the same topicKey already exists in this project, it will be UPDATED instead of creating a new one. ' +\n 'Use memorix_suggest_topic_key to generate a stable key. Good for evolving decisions, architecture docs, etc.',\n ),\n progress: z.object({\n feature: z.string().describe('Feature or task name'),\n status: z.enum(['in-progress', 'completed', 'blocked']).describe('Current status'),\n completion: z.number().optional().describe('Completion percentage 0-100'),\n }).optional().describe('Progress tracking for task/feature observations'),\n },\n },\n async ({ entityName, type, title, narrative, facts, filesModified, concepts, topicKey, progress }) => {\n // Defensive coercion: Claude Code CLI + GLM may send string-encoded arrays\n const safeFacts = facts ? coerceStringArray(facts) : undefined;\n const safeFiles = filesModified ? coerceStringArray(filesModified) : undefined;\n const safeConcepts = concepts ? coerceStringArray(concepts) : undefined;\n\n // ── Compact on Write (dual-mode: LLM or heuristic) ──────────────\n // Search for similar existing memories BEFORE storing.\n // If compact says UPDATE → merge into existing; NONE → skip storing.\n // This keeps memory count low and prevents duplication (Mem0-style).\n let compactAction = '';\n let compactMerged = false;\n if (!topicKey && !progress) {\n try {\n const searchResult = await compactSearch({\n query: `${title} ${narrative.substring(0, 200)}`,\n limit: 5,\n projectId: project.id,\n status: 'active',\n });\n const similarEntries = searchResult.entries.map(e => e);\n if (similarEntries.length > 0) {\n // Fetch full details for comparison\n const similarIds = similarEntries.map(e => e.id);\n const details = await compactDetail(similarIds);\n const existingMemories: ExistingMemory[] = details.documents.map((d, i) => ({\n id: d.observationId,\n title: d.title,\n narrative: d.narrative,\n facts: d.facts,\n score: similarEntries[i]?.score ?? 0,\n }));\n\n const decision = await compactOnWrite(\n { title, narrative, facts: safeFacts ?? [] },\n existingMemories,\n );\n\n if (decision.action === 'UPDATE' && decision.targetId) {\n // Merge into existing memory (Mem0-style UPDATE)\n const targetObs = getObservation(decision.targetId);\n if (targetObs) {\n markInternalWrite();\n await storeObservation({\n entityName: targetObs.entityName,\n type: targetObs.type,\n title: decision.mergedNarrative ? title : targetObs.title,\n narrative: decision.mergedNarrative ?? narrative,\n facts: decision.mergedFacts ?? safeFacts,\n filesModified: safeFiles,\n concepts: safeConcepts,\n projectId: project.id,\n topicKey: targetObs.topicKey,\n progress: progress as import('./types.js').ProgressInfo | undefined,\n });\n compactAction = `🔄 Compact UPDATE: merged into #${decision.targetId} (${decision.reason})`;\n compactMerged = true;\n\n // Return early — we updated existing, no new observation needed\n return {\n content: [{\n type: 'text' as const,\n text: `${compactAction}\\nMode: ${decision.usedLLM ? 'LLM' : 'heuristic'}`,\n }],\n };\n }\n } else if (decision.action === 'NONE') {\n // Memory is redundant — skip storing entirely\n return {\n content: [{\n type: 'text' as const,\n text: `⏭️ Compact SKIP: ${decision.reason}\\nExisting memory #${decision.targetId} already covers this.\\nMode: ${decision.usedLLM ? 'LLM' : 'heuristic'}`,\n }],\n };\n } else if (decision.action === 'DELETE' && decision.targetId) {\n // Old memory is outdated — resolve it, then ADD the new one\n const { resolveObservations } = await import('./memory/observations.js');\n await resolveObservations([decision.targetId], 'resolved');\n compactAction = ` | Compact: resolved outdated #${decision.targetId}`;\n }\n // decision.action === 'ADD' or DELETE fallthrough → proceed to store normally\n if (decision.enrichedFacts && decision.enrichedFacts.length > 0) {\n // LLM extracted additional facts — merge them in\n const currentFacts = safeFacts ?? [];\n const newFacts = decision.enrichedFacts.filter((f: string) => !currentFacts.includes(f));\n if (newFacts.length > 0) {\n compactAction += ` | +${newFacts.length} LLM-extracted facts`;\n }\n }\n }\n } catch { /* compact is best-effort */ }\n }\n\n // ── Standard store flow ─────────────────────────────────────────\n // Ensure entity exists in knowledge graph\n await graphManager.createEntities([\n { name: entityName, entityType: 'auto', observations: [] },\n ]);\n\n // Auto-associate sessionId from active session\n let sessionId: string | undefined;\n try {\n const { getActiveSession } = await import('./memory/session.js');\n const active = await getActiveSession(projectDir, project.id);\n if (active) sessionId = active.id;\n } catch { /* session module not critical */ }\n\n // ── LLM Narrative Compression (premium quality) ─────────────────\n // Compress verbose narratives into concise core knowledge before storing.\n // Reduces token consumption ~60% while preserving all technical facts.\n let finalNarrative = narrative;\n let compressionNote = '';\n try {\n const { compressNarrative } = await import('./llm/quality.js');\n const { compressed, saved, usedLLM } = await compressNarrative(narrative, safeFacts, type);\n if (usedLLM && saved > 0) {\n finalNarrative = compressed;\n compressionNote = ` | compressed -${saved} tokens`;\n }\n } catch { /* compression is best-effort */ }\n\n // Store the observation (may upsert if topicKey matches existing)\n markInternalWrite();\n const { observation: obs, upserted } = await storeObservation({\n entityName,\n type: type as ObservationType,\n title,\n narrative: finalNarrative,\n facts: safeFacts,\n filesModified: safeFiles,\n concepts: safeConcepts,\n projectId: project.id,\n topicKey,\n sessionId,\n progress: progress as import('./types.js').ProgressInfo | undefined,\n });\n\n // Add a reference to the entity's observations\n await graphManager.addObservations([\n { entityName, contents: [`[#${obs.id}] ${title}`] },\n ]);\n\n // Implicit memory: auto-create relations from entity extraction\n const extracted = extractEntities([title, narrative, ...(safeFacts ?? [])].join(' '));\n const autoRelCount = await createAutoRelations(obs, extracted, graphManager);\n\n // Build enrichment summary\n const enrichmentParts: string[] = [];\n const autoFiles = obs.filesModified.filter((f: string) => !(safeFiles ?? []).includes(f));\n const autoConcepts = obs.concepts.filter((c: string) => !(safeConcepts ?? []).includes(c));\n if (autoFiles.length > 0) enrichmentParts.push(`+${autoFiles.length} files extracted`);\n if (autoConcepts.length > 0) enrichmentParts.push(`+${autoConcepts.length} concepts enriched`);\n if (autoRelCount > 0) enrichmentParts.push(`+${autoRelCount} relations auto-created`);\n if (obs.hasCausalLanguage) enrichmentParts.push('causal language detected');\n if (upserted) enrichmentParts.push(`topic upserted (rev ${obs.revisionCount ?? 1})`);\n const enrichment = enrichmentParts.length > 0 ? `\\nAuto-enriched: ${enrichmentParts.join(', ')}` : '';\n\n const action = upserted ? '🔄 Updated' : '✅ Stored';\n\n return {\n content: [\n {\n type: 'text' as const,\n text: `${action} observation #${obs.id} \"${title}\" (~${obs.tokens} tokens)\\nEntity: ${entityName} | Type: ${type} | Project: ${project.id}${obs.topicKey ? ` | Topic: ${obs.topicKey}` : ''}${compactAction}${compressionNote}${enrichment}`,\n },\n ],\n };\n },\n );\n\n /**\n * memorix_suggest_topic_key — Suggest a stable topic key for upserts\n *\n * Use before memorix_store when you want evolving topics to upsert\n * into a single observation instead of creating duplicates.\n */\n server.registerTool(\n 'memorix_suggest_topic_key',\n {\n title: 'Suggest Topic Key',\n description:\n 'Suggest a stable topic_key for memory upserts. Use this before memorix_store when you want evolving topics ' +\n '(like architecture decisions, config docs) to update a single observation over time instead of creating duplicates. ' +\n 'Returns a key like \"architecture/auth-model\" or \"bug/timeout-in-api-gateway\".',\n inputSchema: {\n type: z.string().describe('Observation type (e.g., decision, architecture, bugfix, discovery)'),\n title: z.string().describe('Observation title — used to generate the stable key'),\n },\n },\n async ({ type: obsType, title }) => {\n const { suggestTopicKey } = await import('./memory/observations.js');\n const key = suggestTopicKey(obsType, title);\n\n if (!key) {\n return {\n content: [{ type: 'text' as const, text: 'Could not suggest topic_key from the given input. Provide a more descriptive title.' }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: 'text' as const, text: `Suggested topic_key: \\`${key}\\`\\n\\nUse this as the \\`topicKey\\` parameter in \\`memorix_store\\` to enable upsert behavior.` }],\n };\n },\n );\n\n /**\n * memorix_search — Layer 1: Compact index search\n *\n * Returns a lightweight table of matching observations.\n * ~50-100 tokens per result. Agent scans this to decide what to fetch.\n */\n server.registerTool(\n 'memorix_search',\n {\n title: 'Search Memory',\n description:\n 'Search project memory. Returns a compact index (~50-100 tokens/result). ' +\n 'Use memorix_detail to fetch full content for specific IDs. ' +\n 'Use memorix_timeline to see chronological context. ' +\n 'Searches across all observations stored from any IDE session — enabling cross-session and cross-agent context retrieval.',\n inputSchema: {\n query: z.string().describe('Search query (natural language or keywords)'),\n limit: z.number().optional().describe('Max results (default: 20)'),\n type: z.enum(OBSERVATION_TYPES).optional().describe('Filter by observation type'),\n maxTokens: z.number().optional().describe('Token budget — trim results to fit (0 = unlimited)'),\n scope: z.enum(['project', 'global']).optional().default('project').describe(\n 'Search scope: \"project\" (default) only searches current project, \"global\" searches all projects',\n ),\n since: z.string().optional().describe('Only return observations created after this date (ISO 8601 or natural like \"2025-01-15\")'),\n until: z.string().optional().describe('Only return observations created before this date (ISO 8601 or natural like \"2025-02-01\")'),\n status: z.enum(['active', 'resolved', 'archived', 'all']).optional().default('active').describe(\n 'Filter by memory status. \"active\" (default) shows current memories, \"all\" includes resolved/archived.',\n ),\n },\n },\n async ({ query, limit, type, maxTokens, scope, since, until, status }) => {\n const safeLimit = limit != null ? coerceNumber(limit, 20) : undefined;\n const safeMaxTokens = maxTokens != null ? coerceNumber(maxTokens, 0) : undefined;\n const result = await compactSearch({\n query,\n limit: safeLimit,\n type: type as ObservationType | undefined,\n maxTokens: safeMaxTokens,\n since,\n until,\n // Default to project-scoped search to prevent cross-project pollution.\n // Use scope: 'global' to explicitly search all projects.\n projectId: scope === 'global' ? undefined : project.id,\n status: (status as 'active' | 'resolved' | 'archived' | 'all') ?? 'active',\n });\n\n // Append sync advisory on first search of the session\n let text = result.formatted;\n if (!syncAdvisoryShown && syncAdvisory) {\n text += syncAdvisory;\n syncAdvisoryShown = true;\n }\n\n return {\n content: [\n {\n type: 'text' as const,\n text,\n },\n ],\n };\n },\n );\n\n /**\n * memorix_resolve — Mark memories as resolved/completed\n *\n * Prevents resolved memories from polluting future searches.\n * Default search only returns 'active' memories.\n */\n server.registerTool(\n 'memorix_resolve',\n {\n title: 'Resolve Memories',\n description:\n 'Mark observations as resolved (completed/no longer active). ' +\n 'Resolved memories are hidden from default search but can still be found with status=\"all\". ' +\n 'Use this to mark completed tasks, fixed bugs, or outdated information so they don\\'t pollute future context.',\n inputSchema: {\n ids: z.array(z.number()).describe('Observation IDs to mark as resolved'),\n status: z.enum(['resolved', 'archived']).optional().default('resolved').describe(\n 'Target status: \"resolved\" (default, completed/done) or \"archived\" (permanently hidden)',\n ),\n },\n },\n async ({ ids, status }) => {\n const { resolveObservations } = await import('./memory/observations.js');\n const safeIds = (Array.isArray(ids) ? ids : [ids]).map(id => coerceNumber(id, 0)).filter(id => id > 0);\n const result = await resolveObservations(safeIds, (status as 'resolved' | 'archived') ?? 'resolved');\n\n const parts: string[] = [];\n if (result.resolved.length > 0) {\n parts.push(`✅ Resolved ${result.resolved.length} observation(s): #${result.resolved.join(', #')}`);\n }\n if (result.notFound.length > 0) {\n parts.push(`⚠️ Not found: #${result.notFound.join(', #')}`);\n }\n parts.push('\\nResolved memories are hidden from default search. Use status=\"all\" to include them.');\n\n return {\n content: [{ type: 'text' as const, text: parts.join('\\n') }],\n };\n },\n );\n\n /**\n * memorix_deduplicate — LLM-powered batch deduplication\n *\n * Scans active memories for duplicates/contradictions and auto-resolves them.\n * Requires LLM to be configured (MEMORIX_LLM_API_KEY or OPENAI_API_KEY).\n */\n server.registerTool(\n 'memorix_deduplicate',\n {\n title: 'Deduplicate Memories',\n description:\n 'Scan active memories for duplicates, contradictions, and outdated information using LLM analysis. ' +\n 'Automatically resolves redundant memories. Requires LLM to be configured ' +\n '(set MEMORIX_LLM_API_KEY or OPENAI_API_KEY environment variable). ' +\n 'Without LLM, falls back to basic similarity-based consolidation.',\n inputSchema: {\n query: z.string().optional().describe('Optional query to scope dedup to a topic (default: scan all)'),\n dryRun: z.boolean().optional().default(false).describe('Preview only — show what would be resolved without making changes'),\n },\n },\n async ({ query, dryRun }) => {\n const { getAllObservations, resolveObservations } = await import('./memory/observations.js');\n const allObs = getAllObservations().filter(o => (o.status ?? 'active') === 'active' && o.projectId === project.id);\n\n if (allObs.length < 2) {\n return { content: [{ type: 'text' as const, text: 'Not enough active memories to deduplicate.' }] };\n }\n\n if (!isLLMEnabled()) {\n return {\n content: [{\n type: 'text' as const,\n text: '⚠️ LLM not configured. Set MEMORIX_LLM_API_KEY or OPENAI_API_KEY to enable intelligent dedup.\\n\\n' +\n 'Tip: Use memorix_consolidate for basic similarity-based merging without LLM.',\n }],\n };\n }\n\n // If query provided, search for relevant memories; otherwise take latest 20\n let candidates: typeof allObs;\n if (query) {\n const searchResult = await compactSearch({ query, limit: 20, projectId: project.id, status: 'active' });\n const idSet = new Set(searchResult.entries.map(e => e.id));\n candidates = allObs.filter(o => idSet.has(o.id));\n } else {\n candidates = allObs.slice(-20);\n }\n\n if (candidates.length < 2) {\n return { content: [{ type: 'text' as const, text: 'Not enough memories in scope to deduplicate.' }] };\n }\n\n // Group by entity for focused dedup\n const byEntity = new Map<string, typeof candidates>();\n for (const obs of candidates) {\n const list = byEntity.get(obs.entityName) ?? [];\n list.push(obs);\n byEntity.set(obs.entityName, list);\n }\n\n const actions: string[] = [];\n const toResolve: number[] = [];\n\n for (const [entity, group] of byEntity) {\n if (group.length < 2) continue;\n\n // Compare each pair within entity group\n for (let i = 0; i < group.length; i++) {\n for (let j = i + 1; j < group.length; j++) {\n const newer = group[j];\n const older = group[i];\n try {\n const decision = await deduplicateMemory(\n { title: newer.title, narrative: newer.narrative, facts: newer.facts },\n [{ id: older.id, title: older.title, narrative: older.narrative, facts: older.facts.join('\\n') }],\n );\n if (decision && decision.action === 'UPDATE' && decision.targetId) {\n actions.push(`🔄 #${older.id} \"${older.title}\" → superseded by #${newer.id} (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\n toResolve.push(older.id);\n } else if (decision && decision.action === 'NONE') {\n actions.push(`🗑️ #${newer.id} \"${newer.title}\" → redundant (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\n toResolve.push(newer.id);\n } else if (decision && decision.action === 'DELETE') {\n actions.push(`❌ #${decision.targetId ?? older.id} → outdated (${decision.reason})${decision.usedLLM ? ' [LLM]' : ' [heuristic]'}`);\n toResolve.push(decision.targetId ?? older.id);\n }\n } catch (dedupErr) { actions.push(`⚠️ comparison failed: ${(dedupErr as Error)?.message ?? dedupErr}`); }\n }\n }\n }\n\n if (actions.length === 0) {\n return { content: [{ type: 'text' as const, text: `✅ Scanned ${candidates.length} memories across ${byEntity.size} entities — no duplicates found.` }] };\n }\n\n if (dryRun) {\n return {\n content: [{\n type: 'text' as const,\n text: `🔍 DRY RUN — ${actions.length} action(s) found:\\n\\n${actions.join('\\n')}\\n\\nRun with dryRun=false to apply.`,\n }],\n };\n }\n\n // Apply resolutions\n const unique = [...new Set(toResolve)];\n await resolveObservations(unique, 'resolved');\n\n return {\n content: [{\n type: 'text' as const,\n text: `🧹 Deduplicated: resolved ${unique.length} memory(ies)\\n\\n${actions.join('\\n')}`,\n }],\n };\n },\n );\n\n /**\n * memorix_timeline — Layer 2: Chronological context\n *\n * Shows observations before and after a specific anchor.\n * Helps agents understand the temporal context of an observation.\n */\n server.registerTool(\n 'memorix_timeline',\n {\n title: 'Memory Timeline',\n description:\n 'Get chronological context around a specific observation. ' +\n 'Shows what happened before and after the anchor observation.',\n inputSchema: {\n anchorId: z.number().describe('Observation ID to center the timeline on'),\n depthBefore: z.number().optional().describe('Number of observations before (default: 3)'),\n depthAfter: z.number().optional().describe('Number of observations after (default: 3)'),\n },\n },\n async ({ anchorId, depthBefore, depthAfter }) => {\n const safeAnchor = coerceNumber(anchorId, 0);\n const safeBefore = depthBefore != null ? coerceNumber(depthBefore, 3) : undefined;\n const safeAfter = depthAfter != null ? coerceNumber(depthAfter, 3) : undefined;\n const result = await compactTimeline(\n safeAnchor,\n undefined,\n safeBefore,\n safeAfter,\n );\n\n return {\n content: [\n {\n type: 'text' as const,\n text: result.formatted,\n },\n ],\n };\n },\n );\n\n /**\n * memorix_detail — Layer 3: Full observation details\n *\n * Fetch complete observation content by IDs.\n * Only call after filtering via memorix_search / memorix_timeline.\n * ~500-1000 tokens per observation.\n */\n server.registerTool(\n 'memorix_detail',\n {\n title: 'Memory Details',\n description:\n 'Fetch full observation details by IDs (~500-1000 tokens each). ' +\n 'Always use memorix_search first to find relevant IDs, then fetch only what you need.',\n inputSchema: {\n ids: z.array(z.number()).describe('Observation IDs to fetch (from memorix_search results)'),\n },\n },\n async ({ ids }) => {\n // Defensive coercion: Claude Code CLI + GLM may send \"[16]\" instead of [16]\n const safeIds = coerceNumberArray(ids);\n const result = await compactDetail(safeIds);\n\n return {\n content: [\n {\n type: 'text' as const,\n text: result.documents.length > 0\n ? result.formatted\n : `No observations found for IDs: ${safeIds.join(', ')}`,\n },\n ],\n };\n },\n );\n\n // ================================================================\n // Memorix Retention & Decay Tools (inspired by mcp-memory-service + MemCP)\n // ================================================================\n\n /**\n * memorix_retention — Memory retention status\n *\n * Shows which observations are active, stale, or candidates for archiving.\n * Uses exponential decay scoring from mcp-memory-service.\n */\n server.registerTool(\n 'memorix_retention',\n {\n title: 'Memory Retention Status & Archive',\n description:\n 'Show memory retention status or archive expired memories. ' +\n 'action=\"report\" (default): show active/stale/archive-candidate counts. ' +\n 'action=\"archive\": move expired observations to archive file (reversible). ' +\n 'Uses exponential decay scoring based on importance, age, and access patterns.',\n inputSchema: {\n action: z.enum(['report', 'archive']).optional().describe('Action: \"report\" (show status, default) or \"archive\" (move expired to archive)'),\n },\n },\n async (args: { action?: string }) => {\n const action = args.action ?? 'report';\n const { getRetentionSummary, getArchiveCandidates, rankByRelevance, archiveExpired } = await import('./memory/retention.js');\n const { search } = await import('@orama/orama');\n\n // Handle archive action\n if (action === 'archive') {\n const result = await archiveExpired(projectDir);\n if (result.archived === 0) {\n return {\n content: [{ type: 'text' as const, text: '✅ No expired observations to archive. All memories are within their retention period.' }],\n };\n }\n return {\n content: [{ type: 'text' as const, text: `🗄️ Archived ${result.archived} expired observations → observations.archived.json\\n${result.remaining} active observations remaining.\\n\\nArchived memories can be restored manually if needed.` }],\n };\n }\n\n // Report action (default) — use in-memory observations for reliable lookup\n // (Orama search with empty term is unreliable)\n const { getAllObservations } = await import('./memory/observations.js');\n const allObs = getAllObservations();\n const docs: import('./types.js').MemorixDocument[] = allObs.map(obs => ({\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n }));\n\n if (docs.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No observations found for this project.' }],\n };\n }\n\n const summary = getRetentionSummary(docs);\n const candidates = getArchiveCandidates(docs);\n const ranked = rankByRelevance(docs);\n\n // Format output\n const lines: string[] = [\n `## Memory Retention Status`,\n ``,\n `| Zone | Count |`,\n `|------|-------|`,\n `| Active | ${summary.active} |`,\n `| Stale | ${summary.stale} |`,\n `| Archive Candidates | ${summary.archiveCandidates} |`,\n `| Immune | ${summary.immune} |`,\n `| **Total** | **${docs.length}** |`,\n ``,\n ];\n\n if (candidates.length > 0) {\n lines.push(`### Archive Candidates (${candidates.length})`);\n lines.push(`| ID | Title | Age (days) | Access |`);\n lines.push(`|----|-------|-----------|--------|`);\n for (const c of candidates.slice(0, 10)) {\n const ageDays = Math.round(\n (Date.now() - new Date(c.createdAt).getTime()) / (1000 * 60 * 60 * 24),\n );\n lines.push(`| ${c.observationId} | ${c.title} | ${ageDays}d | ${c.accessCount ?? 0}× |`);\n }\n lines.push('');\n lines.push(`> 💡 Use \\`memorix_retention\\` with \\`action: \"archive\"\\` to move these to archive.`);\n lines.push('');\n }\n\n // Top 5 most relevant\n lines.push(`### Top 5 Most Relevant`);\n lines.push(`| ID | Title | Score | Decay | Access Boost |`);\n lines.push(`|----|-------|-------|-------|-------------|`);\n for (const r of ranked.slice(0, 5)) {\n const doc = docs.find((d) => d.observationId === r.observationId);\n lines.push(\n `| ${r.observationId} | ${doc?.title ?? '?'} | ${r.totalScore.toFixed(3)} | ${r.decayFactor.toFixed(3)} | ${r.accessBoost.toFixed(1)}× |`,\n );\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n // ================================================================\n // MCP Official Memory Server Compatible Tools (optional — 9 tools)\n // Enable via ~/.memorix/settings.json { \"knowledgeGraph\": true }\n // ================================================================\n\n let enableKG = false;\n try {\n const { homedir } = await import('node:os');\n const { join } = await import('node:path');\n const { readFile } = await import('node:fs/promises');\n const raw = await readFile(join(homedir(), '.memorix', 'settings.json'), 'utf-8');\n const s = JSON.parse(raw);\n if (s.knowledgeGraph === true) enableKG = true;\n } catch { /* no settings or parse error — default off */ }\n\n if (enableKG) {\n\n /** create_entities — MCP Official compatible */\n server.registerTool(\n 'create_entities',\n {\n title: 'Create Entities',\n description: 'Create multiple new entities in the knowledge graph',\n inputSchema: {\n entities: z.array(z.object({\n name: z.string().describe('The name of the entity'),\n entityType: z.string().describe('The type of the entity'),\n observations: z.array(z.string()).describe('Initial observations'),\n })),\n },\n },\n async ({ entities }) => {\n const safeEntities = coerceObjectArray<{ name: string; entityType: string; observations: string[] }>(entities);\n const result = await graphManager.createEntities(safeEntities);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n };\n },\n );\n\n /** create_relations — MCP Official compatible, enhanced with typed relation suggestions */\n server.registerTool(\n 'create_relations',\n {\n title: 'Create Relations',\n description:\n 'Create multiple new relations between entities in the knowledge graph. Relations should be in active voice. ' +\n 'Recommended relation types (from mcp-memory-service): causes, fixes, supports, opposes, contradicts, ' +\n 'depends_on, implements, extends, replaces, documents',\n inputSchema: {\n relations: z.array(z.object({\n from: z.string().describe('Source entity name'),\n to: z.string().describe('Target entity name'),\n relationType: z.string().describe('Type of relation (e.g., causes, fixes, supports, depends_on, implements)'),\n })),\n },\n },\n async ({ relations }) => {\n const safeRelations = coerceObjectArray<{ from: string; to: string; relationType: string }>(relations);\n const result = await graphManager.createRelations(safeRelations);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n };\n },\n );\n\n /** add_observations — MCP Official compatible */\n server.registerTool(\n 'add_observations',\n {\n title: 'Add Observations',\n description: 'Add new observations to existing entities in the knowledge graph',\n inputSchema: {\n observations: z.array(z.object({\n entityName: z.string().describe('Entity name to add observations to'),\n contents: z.array(z.string()).describe('Observation contents to add'),\n })),\n },\n },\n async ({ observations }) => {\n const safeObs = coerceObjectArray<{ entityName: string; contents: string[] }>(observations);\n const result = await graphManager.addObservations(safeObs);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],\n };\n },\n );\n\n /** delete_entities — MCP Official compatible */\n server.registerTool(\n 'delete_entities',\n {\n title: 'Delete Entities',\n description: 'Delete multiple entities and their associated relations from the knowledge graph',\n inputSchema: {\n entityNames: z.array(z.string()).describe('Entity names to delete'),\n },\n },\n async ({ entityNames }) => {\n const safeNames = coerceStringArray(entityNames);\n await graphManager.deleteEntities(safeNames);\n return {\n content: [{ type: 'text' as const, text: 'Entities deleted successfully' }],\n };\n },\n );\n\n /** delete_observations — MCP Official compatible */\n server.registerTool(\n 'delete_observations',\n {\n title: 'Delete Observations',\n description: 'Delete specific observations from entities in the knowledge graph',\n inputSchema: {\n deletions: z.array(z.object({\n entityName: z.string().describe('Entity containing the observations'),\n observations: z.array(z.string()).describe('Observations to delete'),\n })),\n },\n },\n async ({ deletions }) => {\n const safeDeletions = coerceObjectArray<{ entityName: string; observations: string[] }>(deletions);\n await graphManager.deleteObservations(safeDeletions);\n return {\n content: [{ type: 'text' as const, text: 'Observations deleted successfully' }],\n };\n },\n );\n\n /** delete_relations — MCP Official compatible */\n server.registerTool(\n 'delete_relations',\n {\n title: 'Delete Relations',\n description: 'Delete multiple relations from the knowledge graph',\n inputSchema: {\n relations: z.array(z.object({\n from: z.string(),\n to: z.string(),\n relationType: z.string(),\n })),\n },\n },\n async ({ relations }) => {\n const safeRelations = coerceObjectArray<{ from: string; to: string; relationType: string }>(relations);\n await graphManager.deleteRelations(safeRelations);\n return {\n content: [{ type: 'text' as const, text: 'Relations deleted successfully' }],\n };\n },\n );\n\n /** read_graph — MCP Official compatible */\n server.registerTool(\n 'read_graph',\n {\n title: 'Read Graph',\n description: 'Read the entire knowledge graph',\n inputSchema: {},\n },\n async () => {\n const graph = await graphManager.readGraph();\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(graph, null, 2) }],\n };\n },\n );\n\n /** search_nodes — MCP Official compatible (basic string search) */\n server.registerTool(\n 'search_nodes',\n {\n title: 'Search Nodes',\n description: 'Search for nodes in the knowledge graph based on a query',\n inputSchema: {\n query: z.string().describe('Search query to match against entity names, types, and observations'),\n },\n },\n async ({ query }) => {\n const graph = await graphManager.searchNodes(query);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(graph, null, 2) }],\n };\n },\n );\n\n /** open_nodes — MCP Official compatible */\n server.registerTool(\n 'open_nodes',\n {\n title: 'Open Nodes',\n description: 'Open specific nodes in the knowledge graph by their names',\n inputSchema: {\n names: z.array(z.string()).describe('Entity names to retrieve'),\n },\n },\n async ({ names }) => {\n const safeNames = coerceStringArray(names);\n const graph = await graphManager.openNodes(safeNames);\n return {\n content: [{ type: 'text' as const, text: JSON.stringify(graph, null, 2) }],\n };\n },\n );\n\n } // end if (enableKG)\n\n // ============================================================\n // Rules Sync Tool (P2 — Memorix differentiator)\n // ============================================================\n\n const RULE_SOURCES: [string, ...string[]] = ['cursor', 'claude-code', 'codex', 'windsurf', 'antigravity', 'copilot', 'kiro', 'opencode', 'trae'];\n\n /** memorix_rules_sync — scan, dedup, and generate rules across agents */\n server.registerTool(\n 'memorix_rules_sync',\n {\n title: 'Rules Sync',\n description:\n 'Scan project for agent rule files (Cursor, Claude Code, Codex, Windsurf, Antigravity, Copilot, Kiro, OpenCode, Trae), ' +\n 'deduplicate, detect conflicts, and optionally generate rules for a target agent format. ' +\n 'Without target: returns sync status report. With target: generates converted rule files.',\n inputSchema: {\n action: z.enum(['status', 'generate']).describe('Action: \"status\" for report, \"generate\" to produce target files'),\n target: z.enum(RULE_SOURCES).optional().describe('Target agent format for generation (required when action=generate)'),\n },\n },\n async ({ action, target }) => {\n const syncer = new RulesSyncer(project.rootPath);\n\n if (action === 'status') {\n const status = await syncer.syncStatus();\n const lines = [\n `## Rules Sync Status`,\n ``,\n `**Sources found:** ${status.sources.join(', ') || 'none'}`,\n `**Total rules:** ${status.totalRules}`,\n `**Unique rules:** ${status.uniqueRules}`,\n `**Conflicts:** ${status.conflicts.length}`,\n ];\n\n if (status.conflicts.length > 0) {\n lines.push('', '### Conflicts');\n for (const c of status.conflicts) {\n lines.push(`- **${c.ruleA.source}** \\`${c.ruleA.id}\\` vs **${c.ruleB.source}** \\`${c.ruleB.id}\\`: ${c.reason}`);\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n }\n\n // action === 'generate'\n if (!target) {\n return {\n content: [{ type: 'text' as const, text: 'Error: target is required for generate action' }],\n isError: true,\n };\n }\n\n const rules = await syncer.scanRules();\n const deduped = syncer.deduplicateRules(rules);\n const effectiveTarget = target === 'opencode' ? 'codex' : target;\n const files = syncer.generateForTarget(deduped, effectiveTarget as RuleSource);\n\n const lines = [\n `## Generated ${files.length} file(s) for ${target}`,\n '',\n ];\n for (const f of files) {\n lines.push(`### \\`${f.filePath}\\``, '```', f.content, '```', '');\n }\n lines.push('> Use these contents to create the rule files in your project.');\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n // ============================================================\n // Workspace Sync Tool (P3 — Cross-Agent Workspace Bridge)\n // ============================================================\n\n const AGENT_TARGETS: [string, ...string[]] = ['windsurf', 'cursor', 'claude-code', 'codex', 'copilot', 'antigravity', 'kiro', 'opencode', 'trae'];\n\n /** memorix_workspace_sync — migrate entire workspace config across agents */\n server.registerTool(\n 'memorix_workspace_sync',\n {\n title: 'Workspace Sync',\n description:\n 'Migrate your entire workspace environment between AI coding agents (Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, OpenCode, Trae). ' +\n 'Syncs MCP server configs, workflows, rules, and skills across IDEs. ' +\n 'Action \"scan\": detect all workspace configs. ' +\n 'Action \"migrate\": generate configs for target agent (preview only). ' +\n 'Action \"apply\": migrate AND write configs to disk with backup/rollback.',\n inputSchema: {\n action: z.enum(['scan', 'migrate', 'apply']).describe('Action: \"scan\" to detect configs, \"migrate\" to preview, \"apply\" to write to disk'),\n target: z.enum(AGENT_TARGETS).optional().describe('Target agent for migration (required for migrate)'),\n items: z.array(z.string()).optional().describe('Selective sync: list specific MCP server or skill names to sync (e.g. [\"figma-remote-mcp-server\", \"create-subagent\"]). Omit to sync all.'),\n },\n },\n async ({ action, target, items }) => {\n const engine = new WorkspaceSyncEngine(project.rootPath);\n\n if (action === 'scan') {\n const scan = await engine.scan();\n const lines = [\n `## Workspace Scan Report`,\n '',\n `### MCP Server Configs`,\n ];\n\n for (const [agent, servers] of Object.entries(scan.mcpConfigs)) {\n if ((servers as MCPServerEntry[]).length > 0) {\n lines.push(`- **${agent}**: ${(servers as MCPServerEntry[]).length} server(s) — ${(servers as MCPServerEntry[]).map((s: MCPServerEntry) => s.name).join(', ')}`);\n }\n }\n\n lines.push('', `### Workflows`);\n if (scan.workflows.length > 0) {\n for (const wf of scan.workflows) {\n lines.push(`- **${wf.name}** (${wf.source}): ${wf.description || '(no description)'}`);\n }\n } else {\n lines.push('- No workflows found');\n }\n\n lines.push('', `### Rules`);\n lines.push(`- ${scan.rulesCount} rule(s) detected across all agents`);\n\n lines.push('', `### Skills`);\n if (scan.skills.length > 0) {\n for (const sk of scan.skills) {\n lines.push(`- **${sk.name}** (${sk.sourceAgent}): ${sk.description || '(no description)'}`);\n }\n } else {\n lines.push('- No skills found');\n }\n\n if (scan.skillConflicts.length > 0) {\n lines.push('', `### ⚠️ Skill Name Conflicts`);\n for (const c of scan.skillConflicts) {\n lines.push(`- **${c.name}**: kept from ${c.kept.sourceAgent}, duplicate in ${c.skipped.sourceAgent}`);\n }\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n }\n\n // action === 'migrate' or 'apply' — both need target\n if (!target) {\n return {\n content: [{ type: 'text' as const, text: 'Error: target is required for migrate/apply action' }],\n isError: true,\n };\n }\n\n if (action === 'apply') {\n const applyResult = await engine.apply(target as AgentTarget, items);\n return {\n content: [{ type: 'text' as const, text: applyResult.migrationSummary }],\n ...(applyResult.success ? {} : { isError: true }),\n };\n }\n\n // action === 'migrate' (preview only)\n const result = await engine.migrate(target as AgentTarget, items);\n const lines = [\n `## Workspace Migration → ${target}`,\n '',\n ];\n\n if (result.mcpServers.generated.length > 0) {\n lines.push('### MCP Config');\n for (const f of result.mcpServers.generated) {\n lines.push(`#### \\`${f.filePath}\\``, '```', f.content, '```', '');\n }\n }\n\n if (result.workflows.generated.length > 0) {\n lines.push('### Workflows');\n for (const f of result.workflows.generated) {\n lines.push(`#### \\`${f.filePath}\\``, '```', f.content, '```', '');\n }\n }\n\n if (result.rules.generated > 0) {\n lines.push(`### Rules`, `- ${result.rules.generated} rule file(s) generated`);\n }\n\n if (result.skills.scanned.length > 0) {\n lines.push('### Skills', `- ${result.skills.scanned.length} skill(s) found, ready to copy:`);\n for (const sk of result.skills.scanned) {\n lines.push(` - **${sk.name}** (from ${sk.sourceAgent})`);\n }\n }\n\n lines.push('', '> Review the generated configs above. Use action \"apply\" to write them to disk.');\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n // ============================================================\n // memorix_skills — Memory-driven project skills\n // ============================================================\n\n server.registerTool(\n 'memorix_skills',\n {\n title: 'Project Skills',\n description:\n 'Memory-driven project skills. ' +\n 'Action \"list\": show all available skills from all agents. ' +\n 'Action \"generate\": auto-generate project-specific skills from observation patterns (gotchas, decisions, how-it-works). ' +\n 'Action \"inject\": return a specific skill\\'s full content for direct use. ' +\n 'Generated skills follow the SKILL.md standard and can be synced across Cursor, Windsurf, Claude Code, Codex, Copilot, Kiro, Antigravity, OpenCode, and Trae.',\n inputSchema: {\n action: z.enum(['list', 'generate', 'inject']).describe('Action: \"list\" to discover skills, \"generate\" to create from memory, \"inject\" to get skill content'),\n name: z.string().optional().describe('Skill name (required for \"inject\")'),\n target: z.enum(AGENT_TARGETS).optional().describe('Target agent to write generated skills to (optional for \"generate\")'),\n write: z.boolean().optional().describe('Whether to write generated skills to disk (default: false, preview only)'),\n },\n },\n async ({ action, name, target, write }) => {\n const { SkillsEngine } = await import('./skills/engine.js');\n const engine = new SkillsEngine(project.rootPath);\n\n if (action === 'list') {\n const skills = engine.listSkills();\n if (skills.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No skills found in any agent directory.\\n\\nSkills are discovered from:\\n- `.cursor/skills/*/SKILL.md`\\n- `.agents/skills/*/SKILL.md`\\n- `.agent/skills/*/SKILL.md`\\n- `.windsurf/skills/*/SKILL.md`\\n- etc.\\n\\nUse action \"generate\" to auto-create skills from your project observations.' }],\n };\n }\n\n const lines = [\n `## Available Skills (${skills.length})`,\n '',\n ];\n for (const sk of skills) {\n lines.push(`- **${sk.name}** (${sk.sourceAgent}): ${sk.description || '(no description)'}`);\n }\n lines.push('', '> Use `action: \"inject\", name: \"<skill-name>\"` to get full skill content.');\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n }\n\n if (action === 'inject') {\n if (!name) {\n return {\n content: [{ type: 'text' as const, text: 'Error: `name` is required for inject action. Use `action: \"list\"` first to see available skills.' }],\n isError: true,\n };\n }\n\n const skill = engine.injectSkill(name);\n if (!skill) {\n return {\n content: [{ type: 'text' as const, text: `Skill \"${name}\" not found. Use \\`action: \"list\"\\` to see available skills.` }],\n isError: true,\n };\n }\n\n return {\n content: [{ type: 'text' as const, text: `## Skill: ${skill.name}\\n**Source**: ${skill.sourceAgent}\\n**Path**: ${skill.sourcePath}\\n\\n---\\n\\n${skill.content}` }],\n };\n }\n\n // action === 'generate'\n const { loadObservationsJson } = await import('./store/persistence.js');\n const allObs = await loadObservationsJson(projectDir) as Array<{\n id?: number; entityName?: string; type?: string; title?: string;\n narrative?: string; facts?: string[]; concepts?: string[];\n filesModified?: string[]; createdAt?: string;\n }>;\n\n const obsData = allObs.map(o => ({\n id: o.id || 0,\n entityName: o.entityName || 'unknown',\n type: o.type || 'discovery',\n title: o.title || '',\n narrative: o.narrative || '',\n facts: o.facts,\n concepts: o.concepts,\n filesModified: o.filesModified,\n createdAt: o.createdAt,\n }));\n\n const generated = engine.generateFromObservations(obsData);\n\n if (generated.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No skill-worthy patterns found yet.\\n\\nSkills are auto-generated when entities accumulate enough observations (3+), especially gotchas, decisions, and how-it-works notes.\\n\\nKeep using memorix_store to build up project knowledge!' }],\n };\n }\n\n const lines = [\n `## Generated Skills (${generated.length})`,\n '',\n 'Based on observation patterns in your project memory:',\n '',\n ];\n\n for (const sk of generated) {\n lines.push(`### ${sk.name}`);\n lines.push(`- **Description**: ${sk.description}`);\n lines.push(`- **Observations**: ${sk.content.split('\\n').length} lines of knowledge`);\n\n if (write && target) {\n const path = engine.writeSkill(sk, target as AgentTarget);\n if (path) {\n lines.push(`- ✅ **Written**: \\`${path}\\``);\n } else {\n lines.push(`- ❌ Failed to write`);\n }\n }\n lines.push('');\n }\n\n if (!write) {\n lines.push('> Preview only. Add `write: true, target: \"<agent>\"` to save skills to disk.');\n }\n\n // Show first generated skill as preview\n if (generated.length > 0) {\n lines.push('', '---', '### Preview: ' + generated[0].name, '', '```markdown', generated[0].content, '```');\n }\n\n return {\n content: [{ type: 'text' as const, text: lines.join('\\n') }],\n };\n },\n );\n\n // ============================================================\n // Mini-Skills — Promote memories to permanent skills\n // ============================================================\n\n /**\n * memorix_promote — Promote observations to permanent mini-skills\n *\n * Converts important memories into permanent, never-decaying mini-skills\n * that are automatically injected into agent context at session_start.\n */\n server.registerTool(\n 'memorix_promote',\n {\n title: 'Promote to Mini-Skill',\n description:\n 'Promote observations to permanent mini-skills that never decay and are auto-injected at session start. ' +\n 'Action \"promote\": convert observation(s) to a mini-skill. ' +\n 'Action \"list\": show all active mini-skills. ' +\n 'Action \"delete\": remove a mini-skill by ID.\\n\\n' +\n 'Mini-skills are project-specific specialized knowledge derived from your actual memories — ' +\n 'gotchas, decisions, fixes that generic online skills cannot provide.',\n inputSchema: {\n action: z.enum(['promote', 'list', 'delete']).describe('Action to perform'),\n observationIds: z.array(z.number()).optional().describe('Observation IDs to promote (required for \"promote\")'),\n skillId: z.number().optional().describe('Mini-skill ID to delete (required for \"delete\")'),\n trigger: z.string().optional().describe('Override: when this skill should be applied'),\n instruction: z.string().optional().describe('Override: what the agent should do'),\n tags: z.array(z.string()).optional().describe('Extra classification tags'),\n },\n },\n async ({ action, observationIds, skillId, trigger, instruction, tags }) => {\n const { promoteToMiniSkill, loadAllMiniSkills, deleteMiniSkill, formatMiniSkillsForInjection } = await import('./skills/mini-skills.js');\n\n if (action === 'list') {\n const skills = await loadAllMiniSkills(projectDir);\n if (skills.length === 0) {\n return {\n content: [{ type: 'text' as const, text: 'No mini-skills found.\\n\\nUse `action: \"promote\", observationIds: [<id>]` to convert important memories into permanent mini-skills.\\nThese will be auto-injected at every session start.' }],\n };\n }\n const formatted = formatMiniSkillsForInjection(skills);\n const lines = [\n formatted,\n '---',\n `Total: ${skills.length} mini-skill(s)`,\n '',\n '> Use `action: \"delete\", skillId: <id>` to remove a mini-skill.',\n ];\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n }\n\n if (action === 'delete') {\n if (skillId == null) {\n return { content: [{ type: 'text' as const, text: 'Error: `skillId` is required for delete action.' }], isError: true };\n }\n const deleted = await deleteMiniSkill(projectDir, skillId);\n if (!deleted) {\n return { content: [{ type: 'text' as const, text: `Mini-skill #${skillId} not found.` }], isError: true };\n }\n return { content: [{ type: 'text' as const, text: `✅ Deleted mini-skill #${skillId}.` }] };\n }\n\n // action === 'promote'\n if (!observationIds || observationIds.length === 0) {\n return { content: [{ type: 'text' as const, text: 'Error: `observationIds` is required for promote action. Use `memorix_search` to find observation IDs.' }], isError: true };\n }\n\n // Load observations by ID\n const { getAllObservations } = await import('./memory/observations.js');\n const allObs = getAllObservations();\n const selected = allObs.filter(o => observationIds.includes(o.id));\n\n if (selected.length === 0) {\n return { content: [{ type: 'text' as const, text: `No observations found for IDs: [${observationIds.join(', ')}]. Use \\`memorix_search\\` to find valid IDs.` }], isError: true };\n }\n\n const skill = await promoteToMiniSkill(projectDir, project.id, selected, { trigger, instruction, tags });\n\n const lines = [\n `✅ Created mini-skill #${skill.id}`,\n '',\n `**${skill.title}**`,\n `**Do**: ${skill.instruction}`,\n `**When**: ${skill.trigger}`,\n ];\n if (skill.facts.length > 0) {\n lines.push('**Facts**:');\n for (const f of skill.facts) lines.push(`- ${f}`);\n }\n lines.push('', `Source: ${selected.length} observation(s) [${selected.map(o => o.id).join(', ')}]`);\n lines.push('', '> This mini-skill will be auto-injected at every `memorix_session_start`.');\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n },\n );\n\n // ============================================================\n // Memory Consolidation\n // ============================================================\n\n /**\n * memorix_consolidate — Merge similar observations to reduce bloat\n */\n server.registerTool(\n 'memorix_consolidate',\n {\n title: 'Consolidate Memories',\n description:\n 'Find and merge similar observations to reduce memory bloat. ' +\n 'Uses text similarity to cluster related observations by entity+type, then merges them into single consolidated records. ' +\n 'Use action=\"preview\" to see candidates without changing data, action=\"execute\" to merge.\\n\\n' +\n 'Example: 10 similar gotchas about Windows paths → 1 consolidated gotcha with all facts preserved.',\n inputSchema: {\n action: z.enum(['preview', 'execute']).describe('preview = dry run showing candidates, execute = actually merge'),\n threshold: z.number().optional().describe('Similarity threshold 0.0-1.0 (default: 0.45). Lower = more aggressive merging'),\n },\n },\n async ({ action, threshold }) => {\n const safeThreshold = threshold != null ? coerceNumber(threshold, 0.45) : undefined;\n const { findConsolidationCandidates, executeConsolidation } = await import('./memory/consolidation.js');\n\n if (action === 'preview') {\n const clusters = await findConsolidationCandidates(projectDir, project.id, { threshold: safeThreshold });\n\n if (clusters.length === 0) {\n return { content: [{ type: 'text' as const, text: '✅ No consolidation candidates found. Your memories are already clean!' }] };\n }\n\n const lines = [`## Consolidation Preview`, `Found **${clusters.length}** clusters to merge:`, ''];\n for (let i = 0; i < clusters.length; i++) {\n const c = clusters[i];\n lines.push(`### Cluster ${i + 1} (${c.ids.length} observations, ~${(c.similarity * 100).toFixed(0)}% similar)`);\n lines.push(`Entity: \\`${c.entityName}\\` | Type: ${c.type}`);\n for (const title of c.titles) lines.push(`- ${title}`);\n lines.push('');\n }\n const totalMergeable = clusters.reduce((sum, c) => sum + c.ids.length - 1, 0);\n lines.push(`> Run with \\`action: \"execute\"\\` to merge. This will remove **${totalMergeable}** duplicate observations.`);\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n }\n\n // Execute\n const result = await executeConsolidation(projectDir, project.id, { threshold: safeThreshold });\n\n if (result.clustersFound === 0) {\n return { content: [{ type: 'text' as const, text: '✅ No consolidation needed. Memories are already clean!' }] };\n }\n\n const lines = [\n `## Consolidation Complete`,\n `- Clusters merged: **${result.clustersFound}**`,\n `- Observations removed: **${result.observationsMerged}**`,\n `- Observations remaining: **${result.observationsAfter}**`,\n '',\n ];\n for (const m of result.merges) {\n lines.push(`- Merged [${m.mergedIds.join(', ')}] → \"${m.resultTitle}\" (${m.factCount} facts)`);\n }\n\n return { content: [{ type: 'text' as const, text: lines.join('\\n') }] };\n },\n );\n\n // ============================================================\n // Session Lifecycle Tools (inspired by Engram)\n // ============================================================\n\n /**\n * memorix_session_start — Start a new coding session\n *\n * Creates a session record and returns context from previous sessions.\n * This is the entry point for session-aware memory management.\n */\n server.registerTool(\n 'memorix_session_start',\n {\n title: 'Start Session',\n description:\n 'Start a new coding session. Returns context from previous sessions so you can resume work seamlessly. ' +\n 'Call this at the beginning of a session to track activity and get injected context. ' +\n 'Any previous active session for this project will be auto-closed.',\n inputSchema: {\n sessionId: z.string().optional().describe('Custom session ID (auto-generated if omitted)'),\n agent: z.string().optional().describe('Agent/IDE name (e.g., \"cursor\", \"windsurf\", \"claude-code\")'),\n },\n },\n async ({ sessionId, agent }) => {\n const { startSession } = await import('./memory/session.js');\n const result = await startSession(projectDir, project.id, { sessionId, agent });\n\n const llmStatus = isLLMEnabled()\n ? `LLM enhanced mode: ${getLLMConfig()?.provider}/${getLLMConfig()?.model} (fact extraction + auto-dedup active)`\n : 'LLM mode: off (set MEMORIX_LLM_API_KEY to enable enhanced memory quality)';\n\n const lines = [\n `✅ Session started: ${result.session.id}`,\n `Project: ${project.name} (${project.id})`,\n result.session.agent ? `Agent: ${result.session.agent}` : '',\n llmStatus,\n '',\n '💡 Tips: Use `memorix_resolve` to mark completed tasks. Use `progress` param in `memorix_store` for task tracking. Use `topicKey` to prevent duplicate memories.',\n '',\n ];\n\n // Inject mini-skills (permanent, never-decaying project knowledge)\n try {\n const { loadAllMiniSkills, formatMiniSkillsForInjection, recordMiniSkillUsage } = await import('./skills/mini-skills.js');\n const miniSkills = await loadAllMiniSkills(projectDir);\n if (miniSkills.length > 0) {\n const formatted = formatMiniSkillsForInjection(miniSkills);\n lines.push('---', '', formatted);\n // Record usage asynchronously (don't block response)\n recordMiniSkillUsage(projectDir, miniSkills.map(s => s.id)).catch(() => {});\n }\n } catch { /* mini-skills not available yet — skip */ }\n\n if (result.previousContext) {\n lines.push('---', '📋 **Context from previous sessions:**', '', result.previousContext);\n } else {\n lines.push('No previous session context found. This appears to be a fresh project.');\n }\n\n // Inject team context if any agents are active\n try {\n const activeAgents = teamRegistry.listAgents({ status: 'active' });\n if (activeAgents.length > 0) {\n lines.push('', '---', '👥 **Team Status:**');\n for (const a of activeAgents) {\n lines.push(`- 🟢 ${a.name}${a.role ? ` (${a.role})` : ''}`);\n }\n\n // Show locked files\n fileLocks.cleanExpired();\n const locks = fileLocks.listLocks();\n if (locks.length > 0) {\n lines.push('', '🔒 **Locked files:**');\n for (const l of locks) {\n const owner = teamRegistry.getAgent(l.lockedBy);\n lines.push(`- ${l.file} — ${owner?.name ?? l.lockedBy.slice(0, 8)}`);\n }\n }\n\n lines.push('', '💡 Use `team_join` to register, `team_inbox` to check messages, `team_task_list available=true` for available work.');\n }\n } catch { /* team context injection is optional */ }\n\n return {\n content: [{ type: 'text' as const, text: lines.filter(Boolean).join('\\n') }],\n };\n },\n );\n\n /**\n * memorix_session_end — End the current coding session\n *\n * Marks the session as completed with a structured summary.\n */\n server.registerTool(\n 'memorix_session_end',\n {\n title: 'End Session',\n description:\n 'End a coding session with a structured summary. This summary will be injected into the next session ' +\n 'so the next agent can resume work seamlessly.\\n\\n' +\n 'Recommended summary format:\\n' +\n '## Goal\\n[What we were working on]\\n\\n' +\n '## Discoveries\\n- [Technical findings, gotchas, learnings]\\n\\n' +\n '## Accomplished\\n- ✅ [Completed tasks]\\n- 🔲 [Pending for next session]\\n\\n' +\n '## Relevant Files\\n- path/to/file — [what changed]',\n inputSchema: {\n sessionId: z.string().describe('Session ID to close (from memorix_session_start)'),\n summary: z.string().optional().describe('Structured session summary (Goal/Discoveries/Accomplished/Files format)'),\n },\n },\n async ({ sessionId, summary }) => {\n const { endSession } = await import('./memory/session.js');\n const session = await endSession(projectDir, sessionId, summary);\n\n if (!session) {\n return {\n content: [{ type: 'text' as const, text: `Session \"${sessionId}\" not found.` }],\n isError: true,\n };\n }\n\n return {\n content: [{\n type: 'text' as const,\n text: `✅ Session \"${sessionId}\" completed.\\nDuration: ${session.startedAt} → ${session.endedAt}\\n${summary ? 'Summary saved for next session context injection.' : 'No summary provided — consider adding one for better cross-session context.'}`,\n }],\n };\n },\n );\n\n /**\n * memorix_session_context — Get context from previous sessions\n *\n * Use this for compaction recovery or to manually retrieve session history.\n */\n server.registerTool(\n 'memorix_session_context',\n {\n title: 'Session Context',\n description:\n 'Get context from previous coding sessions. Use this after compaction to recover lost context, ' +\n 'or to manually review session history. Returns previous session summaries and key observations.',\n inputSchema: {\n limit: z.number().optional().describe('Number of recent sessions to include (default: 3)'),\n },\n },\n async ({ limit }) => {\n const safeLimit = limit != null ? coerceNumber(limit, 3) : 3;\n const { getSessionContext, listSessions } = await import('./memory/session.js');\n const context = await getSessionContext(projectDir, project.id, safeLimit);\n const sessions = await listSessions(projectDir, project.id);\n\n const activeSessions = sessions.filter(s => s.status === 'active');\n const completedSessions = sessions.filter(s => s.status === 'completed');\n\n const header = [\n `## Session Stats`,\n `- Active: ${activeSessions.length}`,\n `- Completed: ${completedSessions.length}`,\n `- Total: ${sessions.length}`,\n '',\n ];\n\n if (!context) {\n return {\n content: [{ type: 'text' as const, text: header.join('\\n') + '\\nNo previous session context available.' }],\n };\n }\n\n return {\n content: [{ type: 'text' as const, text: header.join('\\n') + context }],\n };\n },\n );\n\n // ============================================================\n // Export / Import\n // ============================================================\n\n /**\n * memorix_transfer — Export or import project memories\n */\n server.registerTool(\n 'memorix_transfer',\n {\n title: 'Transfer Memories',\n description:\n 'Export or import project memories. ' +\n 'Action \"export\": export observations and sessions (JSON or Markdown). ' +\n 'Action \"import\": import from a JSON export (re-assigns IDs, skips duplicate topicKeys).',\n inputSchema: {\n action: z.enum(['export', 'import']).describe('Operation: export or import'),\n format: z.enum(['json', 'markdown']).optional().describe('Export format (for export, default: json)'),\n data: z.string().optional().describe('JSON string from a previous export (for import)'),\n },\n },\n async ({ action, format, data: jsonStr }) => {\n if (action === 'export') {\n const { exportAsJson, exportAsMarkdown } = await import('./memory/export-import.js');\n if (format === 'markdown') {\n const md = await exportAsMarkdown(projectDir, project.id);\n return { content: [{ type: 'text' as const, text: md }] };\n }\n const data = await exportAsJson(projectDir, project.id);\n const json = JSON.stringify(data, null, 2);\n return {\n content: [{\n type: 'text' as const,\n text: `Export complete — ${data.stats.observationCount} observations, ${data.stats.sessionCount} sessions\\n\\n\\`\\`\\`json\\n${json}\\n\\`\\`\\`\\n\\n> Use action \"import\" on another machine to restore.`,\n }],\n };\n }\n // import\n if (!jsonStr) return { content: [{ type: 'text' as const, text: '❌ data is required for import' }], isError: true };\n const { importFromJson } = await import('./memory/export-import.js');\n let parsed;\n try { parsed = JSON.parse(jsonStr); } catch {\n return { content: [{ type: 'text' as const, text: 'Invalid JSON. Provide the exact output from export.' }], isError: true };\n }\n const result = await importFromJson(projectDir, parsed);\n return {\n content: [{\n type: 'text' as const,\n text: `Import complete — ${result.observationsImported} observations, ${result.sessionsImported} sessions imported, ${result.skipped} skipped`,\n }],\n };\n },\n );\n\n // ============================================================\n // memorix_dashboard — Launch the web dashboard\n // ============================================================\n\n let dashboardRunning = false;\n\n server.registerTool(\n 'memorix_dashboard',\n {\n title: 'Launch Dashboard',\n description:\n 'Launch the Memorix Web Dashboard in the browser. ' +\n 'Shows knowledge graph, observations, retention scores, and project stats in a visual interface.',\n inputSchema: {\n port: z.number().optional().describe('Port to run the dashboard on (default: 3210)'),\n },\n },\n async ({ port: dashboardPort }) => {\n const portNum = dashboardPort != null ? coerceNumber(dashboardPort, 3210) : 3210;\n const url = `http://localhost:${portNum}`;\n\n if (dashboardRunning) {\n // Verify the dashboard is actually still listening (process may have been killed externally)\n const { createConnection } = await import('node:net');\n const isAlive = await new Promise<boolean>(resolve => {\n const sock = createConnection(portNum, '127.0.0.1');\n sock.once('connect', () => { sock.destroy(); resolve(true); });\n sock.once('error', () => { sock.destroy(); resolve(false); });\n setTimeout(() => { sock.destroy(); resolve(false); }, 1000);\n });\n\n if (isAlive) {\n // Update the dashboard server's current project via API\n const http = await import('node:http');\n const postData = JSON.stringify({ projectId: project.id, projectName: project.name });\n await new Promise<void>(resolve => {\n const req = http.request({\n hostname: '127.0.0.1', port: portNum,\n path: '/api/set-current-project', method: 'POST',\n headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(postData) },\n }, () => resolve());\n req.on('error', () => resolve()); // ignore errors\n req.write(postData);\n req.end();\n });\n\n // Open browser — the dashboard now serves this project as current\n const projectUrl = `${url}?project=${encodeURIComponent(project.id)}`;\n const { exec } = await import('node:child_process');\n const cmd =\n process.platform === 'win32' ? `start \"\" \"${projectUrl}\"` :\n process.platform === 'darwin' ? `open \"${projectUrl}\"` :\n `xdg-open \"${projectUrl}\"`;\n exec(cmd, () => { });\n return {\n content: [{ type: 'text' as const, text: `Dashboard is already running at ${url}. Switched to project: ${project.name} (${project.id}).` }],\n };\n }\n\n // Dashboard process was killed externally — reset flag and fall through to restart\n console.error('[memorix] Dashboard process no longer running, restarting...');\n dashboardRunning = false;\n }\n\n try {\n const pathMod = await import('node:path');\n const fsMod = await import('node:fs');\n const { fileURLToPath } = await import('node:url');\n const { startDashboard } = await import('./dashboard/server.js');\n\n // Try multiple strategies to find the static files directory\n // When running from CLI (dist/cli/index.js), __dirname = dist/cli/, need to go up\n const candidates = [\n pathMod.default.join(__dirname, '..', 'dashboard', 'static'),\n pathMod.default.join(__dirname, 'dashboard', 'static'),\n pathMod.default.join(pathMod.default.dirname(fileURLToPath(import.meta.url)), '..', 'dashboard', 'static'),\n pathMod.default.join(pathMod.default.dirname(fileURLToPath(import.meta.url)), 'dashboard', 'static'),\n ];\n\n // Log all candidates for debugging\n for (const [i, c] of candidates.entries()) {\n const hasIndex = fsMod.existsSync(pathMod.default.join(c, 'index.html'));\n console.error(`[memorix] candidate[${i}]: ${c} (has index.html: ${hasIndex})`);\n }\n\n let staticDir = candidates[0];\n for (const c of candidates) {\n if (fsMod.existsSync(pathMod.default.join(c, 'index.html'))) {\n staticDir = c;\n break;\n }\n }\n console.error(`[memorix] Dashboard staticDir: ${staticDir}`);\n\n // Start in background (non-blocking), disable auto-open (we'll open it ourselves)\n startDashboard(projectDir, portNum, staticDir, project.id, project.name, false, {\n registry: teamRegistry,\n fileLocks,\n taskManager,\n messageBus,\n })\n .then(() => { dashboardRunning = true; })\n .catch((err) => { console.error('[memorix] Dashboard error:', err); dashboardRunning = false; });\n\n // Poll until the server is actually listening (up to 5s)\n const { createConnection } = await import('node:net');\n await new Promise<void>(resolve => {\n const deadline = Date.now() + 5000;\n const tryConnect = () => {\n const sock = createConnection(portNum, '127.0.0.1');\n sock.once('connect', () => { sock.destroy(); resolve(); });\n sock.once('error', () => {\n sock.destroy();\n if (Date.now() < deadline) setTimeout(tryConnect, 100);\n else resolve(); // give up, return anyway\n });\n };\n tryConnect();\n });\n dashboardRunning = true;\n\n // Open browser from MCP side\n const { exec: execCmd } = await import('node:child_process');\n const openCmd =\n process.platform === 'win32' ? `start \"\" \"${url}\"` :\n process.platform === 'darwin' ? `open \"${url}\"` :\n `xdg-open \"${url}\"`;\n execCmd(openCmd, () => { });\n\n return {\n content: [{\n type: 'text' as const,\n text: [\n `Memorix Dashboard started!`,\n ``,\n `URL: ${url}`,\n `Project: ${project.name} (${project.id})`,\n `Static: ${staticDir}`,\n ``,\n `The dashboard has been opened in your default browser.`,\n `It shows your knowledge graph, observations, retention scores, and project stats.`,\n ].join('\\n'),\n }],\n };\n } catch (err) {\n return {\n content: [{ type: 'text' as const, text: `Failed to start dashboard: ${err instanceof Error ? err.message : String(err)}` }],\n };\n }\n },\n );\n\n // ================================================================\n // Team Collaboration Tools (Multi-Agent)\n // ================================================================\n\n const { AgentRegistry } = await import('./team/registry.js');\n const { MessageBus } = await import('./team/messages.js');\n const { FileLockRegistry } = await import('./team/file-locks.js');\n const { TaskManager } = await import('./team/tasks.js');\n\n // Use shared instances (from HTTP server) or create new ones (stdio mode)\n const teamRegistry = sharedTeam?.registry ?? new AgentRegistry();\n const messageBus = sharedTeam?.messageBus ?? new MessageBus(teamRegistry);\n const fileLocks = sharedTeam?.fileLocks ?? new FileLockRegistry();\n const taskManager = sharedTeam?.taskManager ?? new TaskManager();\n\n // File-based persistence for cross-IDE team state sharing (stdio mode only).\n // In HTTP mode, all sessions share in-memory state — no persistence needed.\n let teamPersist: import('./team/persistence.js').TeamPersistence | null = null;\n if (!sharedTeam) {\n const { TeamPersistence } = await import('./team/persistence.js');\n const { join } = await import('node:path');\n teamPersist = new TeamPersistence(\n join(projectDir, 'team-state.json'),\n teamRegistry, messageBus, taskManager, fileLocks,\n );\n await teamPersist.sync();\n }\n const teamSync = () => teamPersist ? teamPersist.sync() : Promise.resolve();\n const teamFlush = () => teamPersist ? teamPersist.flush() : Promise.resolve();\n\n // ── team_manage (join / leave / status) ─────────────────────────\n server.registerTool(\n 'team_manage',\n {\n title: 'Team Management',\n description:\n 'Register, unregister, or list agents in the team. ' +\n 'Action \"join\": register this agent (returns agent ID). ' +\n 'Action \"leave\": mark agent inactive, release locks. ' +\n 'Action \"status\": list all agents with roles and capabilities.',\n inputSchema: {\n action: z.enum(['join', 'leave', 'status']).describe('Operation to perform'),\n name: z.string().optional().describe('Agent name for join (e.g., \"cursor-frontend\")'),\n role: z.string().optional().describe('Agent role for join'),\n capabilities: z.array(z.string()).optional().describe('Agent capabilities for join'),\n agentId: z.string().optional().describe('Agent ID for leave'),\n },\n },\n async ({ action, name, role, capabilities, agentId }) => {\n await teamSync();\n if (action === 'join') {\n const trimmed = (name || '').trim();\n if (!trimmed) return { content: [{ type: 'text' as const, text: '❌ Agent name is required' }], isError: true };\n if (trimmed.length > 100) return { content: [{ type: 'text' as const, text: '❌ Agent name too long (max 100 chars)' }], isError: true };\n const agent = teamRegistry.join({ name: trimmed, role, capabilities: capabilities ? coerceStringArray(capabilities) : undefined });\n await teamFlush();\n return {\n content: [{\n type: 'text' as const,\n text: `✅ Joined team as \"${agent.name}\" (ID: ${agent.id})\\nRole: ${agent.role ?? 'unspecified'}\\nActive agents: ${teamRegistry.getActiveCount()}`,\n }],\n };\n }\n if (action === 'leave') {\n if (!agentId) return { content: [{ type: 'text' as const, text: '❌ agentId is required for leave' }], isError: true };\n const left = teamRegistry.leave(agentId);\n if (!left) return { content: [{ type: 'text' as const, text: '⚠️ Agent not found' }] };\n const releasedLocks = fileLocks.releaseAll(agentId);\n messageBus.clearInbox(agentId);\n await teamFlush();\n const parts: string[] = [];\n if (releasedLocks > 0) parts.push(`released ${releasedLocks} lock(s)`);\n return {\n content: [{\n type: 'text' as const,\n text: `Left team.${parts.length > 0 ? ' ' + parts.join(', ') + '.' : ''}\\nActive agents: ${teamRegistry.getActiveCount()}`,\n }],\n };\n }\n // status\n const agents = teamRegistry.listAgents();\n if (agents.length === 0) {\n return { content: [{ type: 'text' as const, text: 'No agents registered. Use action \"join\" to register.' }] };\n }\n const lines = agents.map(a =>\n `${a.status === 'active' ? '●' : '○'} ${a.name} (${a.id}) — ${a.role ?? 'no role'} [${a.capabilities.join(', ') || '-'}]`,\n );\n return {\n content: [{\n type: 'text' as const,\n text: `Team: ${teamRegistry.getActiveCount()} active / ${agents.length} total\\n\\n${lines.join('\\n')}`,\n }],\n };\n },\n );\n\n // ── team_file_lock (lock / unlock / status) ───────────────────\n server.registerTool(\n 'team_file_lock',\n {\n title: 'File Lock Management',\n description:\n 'Advisory file locks to prevent conflicting edits. Auto-releases after 10 min TTL. ' +\n 'Action \"lock\": acquire lock. Action \"unlock\": release lock. Action \"status\": check lock status.',\n inputSchema: {\n action: z.enum(['lock', 'unlock', 'status']).describe('Operation to perform'),\n file: z.string().optional().describe('File path (required for lock/unlock, optional for status — omit to list all)'),\n agentId: z.string().optional().describe('Agent ID (required for lock/unlock)'),\n },\n },\n async ({ action, file, agentId }) => {\n await teamSync();\n fileLocks.cleanExpired();\n if (action === 'lock') {\n if (!file || !agentId) return { content: [{ type: 'text' as const, text: '❌ file and agentId are required for lock' }], isError: true };\n const agent = teamRegistry.getAgent(agentId);\n if (!agent || agent.status !== 'active') {\n return { content: [{ type: 'text' as const, text: `❌ Unknown or inactive agent: ${agentId.slice(0, 8)}…` }], isError: true };\n }\n const result = fileLocks.lock(file, agentId);\n await teamFlush();\n if (result.success) return { content: [{ type: 'text' as const, text: `Locked: ${file}` }] };\n const owner = teamRegistry.getAgent(result.lockedBy);\n return { content: [{ type: 'text' as const, text: `Denied — locked by ${owner?.name ?? result.lockedBy.slice(0, 8)}` }], isError: true };\n }\n if (action === 'unlock') {\n if (!file || !agentId) return { content: [{ type: 'text' as const, text: '❌ file and agentId are required for unlock' }], isError: true };\n const released = fileLocks.unlock(file, agentId);\n await teamFlush();\n return { content: [{ type: 'text' as const, text: released ? `Unlocked: ${file}` : `Cannot unlock: not owner or not locked` }] };\n }\n // status\n if (file) {\n const status = fileLocks.getStatus(file);\n if (!status) return { content: [{ type: 'text' as const, text: `${file} — unlocked` }] };\n const owner = teamRegistry.getAgent(status.lockedBy);\n return { content: [{ type: 'text' as const, text: `${file} — locked by ${owner?.name ?? status.lockedBy.slice(0, 8)} (expires ${status.expiresAt.toISOString()})` }] };\n }\n const all = fileLocks.listLocks();\n if (all.length === 0) return { content: [{ type: 'text' as const, text: 'No files locked' }] };\n const lines = all.map(l => {\n const owner = teamRegistry.getAgent(l.lockedBy);\n return `${l.file} — ${owner?.name ?? l.lockedBy.slice(0, 8)}`;\n });\n return { content: [{ type: 'text' as const, text: `Locked files (${all.length}):\\n${lines.join('\\n')}` }] };\n },\n );\n\n // ── team_task (create / claim / complete / list) ──────────────\n server.registerTool(\n 'team_task',\n {\n title: 'Task Board',\n description:\n 'Create, claim, complete, or list tasks in the team task board. Supports dependencies. ' +\n 'Action \"create\": create a task. Action \"claim\": assign to yourself. ' +\n 'Action \"complete\": mark done with result. Action \"list\": show tasks.',\n inputSchema: {\n action: z.enum(['create', 'claim', 'complete', 'list']).describe('Operation to perform'),\n description: z.string().optional().describe('Task description (for create)'),\n deps: z.array(z.string()).optional().describe('Dependency task IDs (for create)'),\n taskId: z.string().optional().describe('Task ID (for claim/complete)'),\n agentId: z.string().optional().describe('Agent ID (for claim/complete)'),\n result: z.string().optional().describe('Result summary (for complete)'),\n status: z.enum(['pending', 'in_progress', 'completed', 'failed']).optional().describe('Filter by status (for list)'),\n available: z.boolean().optional().describe('Show only claimable tasks (for list)'),\n },\n },\n async ({ action, description: desc, deps, taskId, agentId, result, status, available }) => {\n await teamSync();\n try {\n if (action === 'create') {\n if (!desc) return { content: [{ type: 'text' as const, text: '❌ description is required for create' }], isError: true };\n const task = taskManager.create({ description: desc, deps: deps ? coerceStringArray(deps) : undefined });\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Task created: ${task.id} \"${desc}\"${task.deps.length > 0 ? ` (depends on ${task.deps.length})` : ''}` }] };\n }\n if (action === 'claim') {\n if (!taskId || !agentId) return { content: [{ type: 'text' as const, text: '❌ taskId and agentId required for claim' }], isError: true };\n const agent = teamRegistry.getAgent(agentId);\n if (!agent || agent.status !== 'active') return { content: [{ type: 'text' as const, text: `❌ Unknown or inactive agent` }], isError: true };\n const task = taskManager.claim(taskId, agentId);\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Task claimed by ${agent.name}: \"${task.description}\"` }] };\n }\n if (action === 'complete') {\n if (!taskId || !agentId || !result) return { content: [{ type: 'text' as const, text: '❌ taskId, agentId, and result required for complete' }], isError: true };\n const existingTask = taskManager.getTask(taskId);\n const allowRescue = existingTask?.assignee ? teamRegistry.getAgent(existingTask.assignee)?.status !== 'active' : false;\n const task = taskManager.complete(taskId, agentId, result, allowRescue);\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Task completed${allowRescue ? ' (rescued)' : ''}: \"${task.description}\"\\nResult: ${result}` }] };\n }\n // list\n const list = available ? taskManager.getAvailable() : taskManager.list(status ? { status } : undefined);\n if (list.length === 0) return { content: [{ type: 'text' as const, text: available ? 'No tasks available to claim' : 'No tasks found' }] };\n const statusIcon: Record<string, string> = { pending: '[ ]', in_progress: '[~]', completed: '[x]', failed: '[!]' };\n const lines = list.map(t => {\n const assignee = t.assignee ? teamRegistry.getAgent(t.assignee)?.name ?? t.assignee.slice(0, 8) : 'unassigned';\n return `${statusIcon[t.status] ?? '[ ]'} ${t.id} \"${t.description}\" — ${assignee}${t.deps.length > 0 ? ` [deps: ${t.deps.length}]` : ''}`;\n });\n return { content: [{ type: 'text' as const, text: `Tasks (${list.length}):\\n${lines.join('\\n')}` }] };\n } catch (err) {\n return { content: [{ type: 'text' as const, text: `❌ ${(err as Error).message}` }], isError: true };\n }\n },\n );\n\n // ── team_message (send / broadcast / inbox) ───────────────────\n server.registerTool(\n 'team_message',\n {\n title: 'Team Messaging',\n description:\n 'Send, broadcast, or read messages between agents. ' +\n 'Action \"send\": direct message to one agent. Action \"broadcast\": message all active agents. ' +\n 'Action \"inbox\": read this agent\\'s inbox.',\n inputSchema: {\n action: z.enum(['send', 'broadcast', 'inbox']).describe('Operation to perform'),\n from: z.string().optional().describe('Sender agent ID (for send/broadcast)'),\n to: z.string().optional().describe('Receiver agent ID (for send)'),\n type: z.enum(['request', 'response', 'info', 'announcement', 'contract', 'error']).optional().describe('Message type (for send/broadcast)'),\n content: z.string().optional().describe('Message content (for send/broadcast)'),\n agentId: z.string().optional().describe('Agent ID (for inbox)'),\n markRead: z.boolean().optional().default(false).describe('Mark messages as read (for inbox)'),\n },\n },\n async ({ action, from, to, type: msgType, content, agentId, markRead }) => {\n await teamSync();\n if (action === 'send') {\n if (!from || !to || !msgType || !content) return { content: [{ type: 'text' as const, text: '❌ from, to, type, and content required for send' }], isError: true };\n if (content.length > 10_000) return { content: [{ type: 'text' as const, text: '❌ Message too large (max 10KB)' }], isError: true };\n try {\n const msg = messageBus.send({ from, to, type: msgType, content });\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Message sent (${msgType}) to ${to.slice(0, 8)}… | ID: ${msg.id.slice(0, 8)}…` }] };\n } catch (err) {\n return { content: [{ type: 'text' as const, text: `❌ ${(err as Error).message}` }], isError: true };\n }\n }\n if (action === 'broadcast') {\n if (!from || !msgType || !content) return { content: [{ type: 'text' as const, text: '❌ from, type, and content required for broadcast' }], isError: true };\n if (content.length > 10_000) return { content: [{ type: 'text' as const, text: '❌ Message too large (max 10KB)' }], isError: true };\n const msgs = messageBus.broadcast({ from, type: msgType, content });\n await teamFlush();\n return { content: [{ type: 'text' as const, text: `Broadcast (${msgType}) to ${msgs.length} agent(s)` }] };\n }\n // inbox\n const inboxId = agentId || from || '';\n if (!inboxId) return { content: [{ type: 'text' as const, text: '❌ agentId required for inbox' }], isError: true };\n const inbox = messageBus.getInbox(inboxId);\n const unread = messageBus.getUnreadCount(inboxId);\n if (inbox.length === 0) return { content: [{ type: 'text' as const, text: 'Inbox empty' }] };\n if (markRead) {\n messageBus.markRead(inboxId, inbox.map(m => m.id));\n await teamFlush();\n }\n const lines = inbox.slice(-10).map(m => {\n const sender = teamRegistry.getAgent(m.from);\n return `${m.read ? ' ' : '*'} [${m.type}] from ${sender?.name ?? m.from.slice(0, 8)}: ${m.content.slice(0, 100)}`;\n });\n return { content: [{ type: 'text' as const, text: `Inbox: ${unread} unread / ${inbox.length} total\\n\\n${lines.join('\\n')}` }] };\n },\n );\n\n // Deferred initialization — runs AFTER transport connect so MCP handshake isn't blocked.\n // Hooks auto-install, sync advisory scan, and file watcher are non-essential for tool\n // functionality and can take 30-60s on machines with many IDEs/projects.\n const deferredInit = async () => {\n // Auto-install hooks for newly detected agents\n // Respects ~/.memorix/settings.json { \"autoInstallHooks\": false } to skip\n try {\n let autoInstall = true;\n try {\n const { homedir } = await import('node:os');\n const { join } = await import('node:path');\n const { readFile } = await import('node:fs/promises');\n const settingsPath = join(homedir(), '.memorix', 'settings.json');\n const raw = await readFile(settingsPath, 'utf-8');\n const settings = JSON.parse(raw);\n if (settings.autoInstallHooks === false) {\n autoInstall = false;\n console.error('[memorix] autoInstallHooks disabled in ~/.memorix/settings.json — skipping hook auto-install');\n }\n } catch { /* no settings file or parse error — default to auto-install */ }\n\n if (autoInstall) {\n const { getHookStatus, installHooks, detectInstalledAgents } = await import('./hooks/installers/index.js');\n const { join } = await import('node:path');\n const { access } = await import('node:fs/promises');\n const workDir = cwd ?? process.cwd();\n const statuses = await getHookStatus(workDir);\n const installedAgents = new Set(statuses.filter((s) => s.installed).map((s) => s.agent));\n const detectedAgents = await detectInstalledAgents();\n\n // Map agent → project-level marker directory that the IDE creates on its own.\n // Only auto-install hooks if this directory already exists in the project,\n // preventing creation of unwanted IDE config dirs (e.g. .windsurf/ in a Cursor project).\n const AGENT_MARKER_DIR: Record<string, string> = {\n claude: '.claude',\n windsurf: '.windsurf',\n cursor: '.cursor',\n copilot: '.vscode',\n opencode: '.opencode',\n kiro: '.kiro',\n antigravity: '.gemini',\n trae: '.trae',\n };\n\n for (const agent of detectedAgents) {\n if (installedAgents.has(agent)) continue;\n // Skip if the IDE's marker directory doesn't exist in this project\n const markerDir = AGENT_MARKER_DIR[agent];\n if (markerDir) {\n try { await access(join(workDir, markerDir)); } catch { continue; }\n }\n try {\n const config = await installHooks(agent, workDir);\n console.error(`[memorix] Auto-installed hooks for ${agent} → ${config.configPath}`);\n } catch { /* skip */ }\n }\n }\n } catch { /* hooks install is optional */ }\n\n // Sync advisory: compute once, show on first memorix_search\n try {\n const engine = new WorkspaceSyncEngine(project.rootPath);\n const scan = await engine.scan();\n const lines: string[] = [];\n\n const totalMCP = Object.values(scan.mcpConfigs).reduce((sum, arr) => sum + arr.length, 0);\n const totalSkills = scan.skills.length;\n const totalRules = scan.rulesCount;\n const totalWorkflows = scan.workflows.length;\n\n if (totalMCP > 0 || totalSkills > 0 || totalRules > 0 || totalWorkflows > 0) {\n lines.push('', '---', '🔄 **Cross-Agent Sync Available**');\n for (const [agent, servers] of Object.entries(scan.mcpConfigs)) {\n const list = servers as MCPServerEntry[];\n if (list.length > 0) {\n lines.push(`- **${agent}** MCP: ${list.map(s => s.name).join(', ')}`);\n }\n }\n if (totalSkills > 0) {\n const byAgent = new Map<string, string[]>();\n for (const sk of scan.skills) {\n const arr = byAgent.get(sk.sourceAgent) || [];\n arr.push(sk.name);\n byAgent.set(sk.sourceAgent, arr);\n }\n for (const [agent, names] of byAgent) {\n lines.push(`- **${agent}** skills: ${names.join(', ')}`);\n }\n }\n if (scan.skillConflicts.length > 0) lines.push(` ⚠️ ${scan.skillConflicts.length} name conflict(s)`);\n if (totalRules > 0) lines.push(`- **${totalRules} rule(s)** found`);\n if (totalWorkflows > 0) lines.push(`- **${totalWorkflows} workflow(s)** found`);\n lines.push('');\n lines.push('⚠️ IMPORTANT INSTRUCTIONS FOR AI AGENT:');\n lines.push('1. Tell the user what configs/skills are available from other agents (list them).');\n lines.push('2. Ask which ones they want to sync.');\n lines.push('3. DO NOT manually copy files or run shell commands to sync.');\n lines.push('4. ONLY use `memorix_workspace_sync action=\"apply\" target=\"<agent>\"` to sync all,');\n lines.push(' or add `items=[\"name1\",\"name2\"]` to sync specific items selectively.');\n syncAdvisory = lines.join('\\n');\n }\n console.error(`[memorix] Sync advisory: ${syncAdvisory ? 'available' : 'nothing to sync'}`);\n } catch { /* sync scan is optional */ }\n\n // ── Background retention cleanup ────────────────────────────────\n // Archive expired memories automatically so users never need to run it manually.\n try {\n const { archiveExpired } = await import('./memory/retention.js');\n const archiveResult = await archiveExpired(projectDir);\n if (archiveResult.archived > 0) {\n console.error(`[memorix] Auto-archived ${archiveResult.archived} expired observation(s)`);\n }\n } catch { /* retention cleanup is optional */ }\n\n // ── Background consolidation ─────────────────────────────────────\n // With LLM: semantic dedup (higher quality). Without: Jaccard similarity.\n // Users who configure an API key want quality — each call is only ~500 tokens.\n try {\n if (isLLMEnabled()) {\n const { getAllObservations, resolveObservations } = await import('./memory/observations.js');\n const { deduplicateMemory } = await import('./llm/memory-manager.js');\n const allObs = getAllObservations().filter(o => (o.status ?? 'active') === 'active' && o.projectId === project.id);\n if (allObs.length > 10) {\n const grouped = new Map<string, typeof allObs>();\n for (const obs of allObs) {\n const key = `${obs.entityName}::${obs.type}`;\n if (!grouped.has(key)) grouped.set(key, []);\n grouped.get(key)!.push(obs);\n }\n const toResolve: number[] = [];\n for (const [, group] of grouped) {\n if (group.length < 2) continue;\n group.sort((a, b) => new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime());\n for (let i = 0; i < group.length - 1 && i < 5; i++) {\n try {\n const older = group[i], newer = group[i + 1];\n const decision = await deduplicateMemory(\n { title: newer.title, narrative: newer.narrative, facts: newer.facts },\n [{ id: older.id, title: older.title, narrative: older.narrative, facts: older.facts.join('\\n') }],\n );\n if (decision && (decision.action === 'UPDATE' || decision.action === 'NONE')) {\n toResolve.push(decision.action === 'UPDATE' ? older.id : newer.id);\n } else if (decision?.action === 'DELETE' && decision.targetId) {\n toResolve.push(decision.targetId);\n }\n } catch { /* skip individual comparison errors */ }\n }\n }\n if (toResolve.length > 0) {\n await resolveObservations([...new Set(toResolve)], 'resolved');\n console.error(`[memorix] Auto-dedup (LLM): resolved ${toResolve.length} redundant observation(s)`);\n }\n }\n } else {\n const { executeConsolidation } = await import('./memory/consolidation.js');\n const result = await executeConsolidation(projectDir, project.id, { threshold: 0.55 });\n if (result.observationsMerged > 0) {\n console.error(`[memorix] Auto-consolidated: merged ${result.observationsMerged} duplicate(s) across ${result.clustersFound} cluster(s)`);\n }\n }\n } catch { /* consolidation is optional */ }\n\n // Watch for external writes (e.g., from hook processes) and hot-reload.\n // Uses watchFile (polling) instead of watch because atomicWriteFile uses\n // rename(), which changes the file inode — fs.watch loses track on Windows.\n const observationsFile = projectDir + '/observations.json';\n let reloadDebounce: ReturnType<typeof setTimeout> | null = null;\n let reloading = false; // guard: skip if a reload is already in progress\n // lastInternalWriteMs + markInternalWrite are module-level (see top of file)\n try {\n watchFile(observationsFile, { interval: 5000 }, (curr, prev) => {\n if (curr.mtimeMs === prev.mtimeMs) return; // no actual change\n // Skip reload if a MCP tool wrote recently — data is already in memory\n if (Date.now() - lastInternalWriteMs < 10_000) return;\n if (reloading) return; // skip — previous reload still running\n if (reloadDebounce) clearTimeout(reloadDebounce);\n reloadDebounce = setTimeout(async () => {\n if (reloading) return;\n reloading = true;\n try {\n await resetDb();\n await initObservations(projectDir);\n const count = await reindexObservations();\n if (count > 0) {\n console.error(`[memorix] Hot-reloaded ${count} observations (external write detected)`);\n }\n } catch { /* silent */ }\n reloading = false;\n }, 3000);\n });\n console.error(`[memorix] Watching for external writes (hooks hot-reload enabled)`);\n } catch {\n console.error(`[memorix] Warning: could not watch observations file for hot-reload`);\n }\n };\n\n return { server, graphManager, projectId: project.id, deferredInit };\n}\n","/**\n * Knowledge Graph Manager\n *\n * Manages the Entity-Relation knowledge graph.\n * Source: MCP Official Memory Server v0.6.3 (complete rewrite with same API).\n *\n * Key differences from official implementation:\n * - Uses per-project JSONL files (official uses single file)\n * - Async initialization with persistence layer\n * - Project-scoped operations\n */\n\nimport type { Entity, Relation, KnowledgeGraph } from '../types.js';\nimport { saveGraphJsonl, loadGraphJsonl } from '../store/persistence.js';\nimport { withFileLock } from '../store/file-lock.js';\n\nexport class KnowledgeGraphManager {\n private entities: Entity[] = [];\n private relations: Relation[] = [];\n private projectDir: string;\n private initialized = false;\n /** Index: lowercase entity name → Entity for O(1) lookups */\n private entityIndex = new Map<string, Entity>();\n\n constructor(projectDir: string) {\n this.projectDir = projectDir;\n }\n\n /** Rebuild the entity name index */\n private rebuildIndex(): void {\n this.entityIndex.clear();\n for (const e of this.entities) {\n this.entityIndex.set(e.name.toLowerCase(), e);\n }\n }\n\n /** Load graph from disk on first access */\n async init(): Promise<void> {\n if (this.initialized) return;\n const data = await loadGraphJsonl(this.projectDir);\n this.entities = data.entities;\n this.relations = data.relations;\n this.rebuildIndex();\n this.initialized = true;\n }\n\n /** Find entity by name (case-insensitive, O(1)) */\n findEntityByName(name: string): Entity | undefined {\n return this.entityIndex.get(name.toLowerCase());\n }\n\n /** Get all entity names as a Set (lowercase, for fast membership checks) */\n getEntityNameSet(): Set<string> {\n return new Set(this.entityIndex.keys());\n }\n\n /** Persist current state to disk with file lock (cross-process safe) */\n private async save(): Promise<void> {\n await withFileLock(this.projectDir, async () => {\n await saveGraphJsonl(this.projectDir, this.entities, this.relations);\n });\n }\n\n /** Create new entities (skip duplicates by name) */\n async createEntities(entities: Entity[]): Promise<Entity[]> {\n await this.init();\n const newEntities = entities.filter(\n (e) => !this.entityIndex.has(e.name.toLowerCase()),\n );\n this.entities.push(...newEntities);\n if (newEntities.length > 0) this.rebuildIndex();\n await this.save();\n return newEntities;\n }\n\n /** Create new relations (skip duplicates) */\n async createRelations(relations: Relation[]): Promise<Relation[]> {\n await this.init();\n const newRelations = relations.filter(\n (r) =>\n !this.relations.some(\n (existing) =>\n existing.from === r.from &&\n existing.to === r.to &&\n existing.relationType === r.relationType,\n ),\n );\n this.relations.push(...newRelations);\n await this.save();\n return newRelations;\n }\n\n /** Add observations to existing entities */\n async addObservations(\n observations: { entityName: string; contents: string[] }[],\n ): Promise<{ entityName: string; addedObservations: string[] }[]> {\n await this.init();\n const results = observations.map((o) => {\n const entity = this.entities.find((e) => e.name === o.entityName);\n if (!entity) {\n throw new Error(`Entity with name ${o.entityName} not found`);\n }\n const newObs = o.contents.filter((c) => !entity.observations.includes(c));\n entity.observations.push(...newObs);\n return { entityName: o.entityName, addedObservations: newObs };\n });\n await this.save();\n return results;\n }\n\n /** Delete entities and their associated relations */\n async deleteEntities(entityNames: string[]): Promise<void> {\n await this.init();\n this.entities = this.entities.filter((e) => !entityNames.includes(e.name));\n this.relations = this.relations.filter(\n (r) => !entityNames.includes(r.from) && !entityNames.includes(r.to),\n );\n this.rebuildIndex();\n await this.save();\n }\n\n /** Delete specific observations from entities */\n async deleteObservations(\n deletions: { entityName: string; observations: string[] }[],\n ): Promise<void> {\n await this.init();\n for (const d of deletions) {\n const entity = this.entities.find((e) => e.name === d.entityName);\n if (entity) {\n entity.observations = entity.observations.filter(\n (o) => !d.observations.includes(o),\n );\n }\n }\n await this.save();\n }\n\n /** Delete specific relations */\n async deleteRelations(relations: Relation[]): Promise<void> {\n await this.init();\n this.relations = this.relations.filter(\n (r) =>\n !relations.some(\n (del) =>\n r.from === del.from &&\n r.to === del.to &&\n r.relationType === del.relationType,\n ),\n );\n await this.save();\n }\n\n /** Read the entire graph */\n async readGraph(): Promise<KnowledgeGraph> {\n await this.init();\n return { entities: this.entities, relations: this.relations };\n }\n\n /** Search nodes by query string (upgraded from official's basic includes) */\n async searchNodes(query: string): Promise<KnowledgeGraph> {\n await this.init();\n const lowerQuery = query.toLowerCase();\n\n const filteredEntities = this.entities.filter(\n (e) =>\n e.name.toLowerCase().includes(lowerQuery) ||\n e.entityType.toLowerCase().includes(lowerQuery) ||\n e.observations.some((o) => o.toLowerCase().includes(lowerQuery)),\n );\n\n const filteredNames = new Set(filteredEntities.map((e) => e.name));\n\n const filteredRelations = this.relations.filter(\n (r) => filteredNames.has(r.from) && filteredNames.has(r.to),\n );\n\n return { entities: filteredEntities, relations: filteredRelations };\n }\n\n /** Open specific nodes by name */\n async openNodes(names: string[]): Promise<KnowledgeGraph> {\n await this.init();\n\n const filteredEntities = this.entities.filter((e) => names.includes(e.name));\n const filteredNames = new Set(filteredEntities.map((e) => e.name));\n\n const filteredRelations = this.relations.filter(\n (r) => filteredNames.has(r.from) && filteredNames.has(r.to),\n );\n\n return { entities: filteredEntities, relations: filteredRelations };\n }\n}\n","/**\n * Auto-Relation Creator\n *\n * Automatically creates Knowledge Graph relations from entity extraction.\n * Inspired by mcp-memory-service's typed relationships and MemCP's MAGMA 4-graph.\n *\n * When an observation is stored:\n * 1. Extract entities from narrative (files, modules, CamelCase)\n * 2. Find matching existing entities in the graph\n * 3. Auto-create relations: \"references\", \"modifies\", or \"causes\" (if causal)\n *\n * This is \"implicit memory\" — the agent doesn't need to call create_relations.\n */\n\nimport type { Observation, Relation } from '../types.js';\nimport type { KnowledgeGraphManager } from './graph.js';\nimport type { ExtractedEntities } from './entity-extractor.js';\n\n/**\n * Infer relation type based on observation type and causal language.\n */\nfunction inferRelationType(obs: Observation): string {\n if (obs.hasCausalLanguage) return 'causes';\n\n switch (obs.type) {\n case 'problem-solution':\n return 'fixes';\n case 'decision':\n case 'trade-off':\n return 'decides';\n case 'what-changed':\n return 'modifies';\n case 'gotcha':\n return 'warns_about';\n default:\n return 'references';\n }\n}\n\n/**\n * Auto-create relations from a stored observation.\n *\n * Scans the knowledge graph for entities matching extracted file names,\n * modules, and identifiers, then creates typed relations.\n *\n * Returns the number of relations created.\n */\nexport async function createAutoRelations(\n obs: Observation,\n extracted: ExtractedEntities,\n graphManager: KnowledgeGraphManager,\n): Promise<number> {\n const relationType = inferRelationType(obs);\n const relations: Relation[] = [];\n\n // Skip self-references\n const selfName = obs.entityName.toLowerCase();\n\n // Check extracted identifiers against existing entities (O(1) lookups via index)\n const candidates = [\n ...extracted.identifiers,\n ...extracted.files.map((f) => f.split('/').pop()?.replace(/\\.\\w+$/, '') ?? ''),\n ...extracted.modules.map((m) => m.split(/[./]/).pop() ?? ''),\n ].filter((c) => c.length >= 3);\n\n for (const candidate of candidates) {\n const lower = candidate.toLowerCase();\n if (lower === selfName) continue;\n\n const matchedEntity = graphManager.findEntityByName(candidate);\n if (matchedEntity) {\n relations.push({\n from: obs.entityName,\n to: matchedEntity.name,\n relationType,\n });\n }\n }\n\n // Also create relations from explicit filesModified → existing entities\n for (const file of obs.filesModified) {\n const basename = file.split('/').pop()?.replace(/\\.\\w+$/, '') ?? '';\n if (basename.length < 3 || basename.toLowerCase() === selfName) continue;\n\n const matchedEntity = graphManager.findEntityByName(basename);\n if (matchedEntity) {\n relations.push({\n from: obs.entityName,\n to: matchedEntity.name,\n relationType: 'modifies',\n });\n }\n }\n\n if (relations.length === 0) return 0;\n\n // Deduplicate\n const unique = relations.filter(\n (r, i, arr) =>\n arr.findIndex(\n (o) => o.from === r.from && o.to === r.to && o.relationType === r.relationType,\n ) === i,\n );\n\n const created = await graphManager.createRelations(unique);\n return created.length;\n}\n","/**\n * Compact Engine\n *\n * Orchestrates the 3-layer Progressive Disclosure workflow.\n * Source: claude-mem's proven architecture (27K stars, ~10x token savings).\n *\n * Layer 1 (search) → Compact index with IDs (~50-100 tokens/result)\n * Layer 2 (timeline) → Chronological context around an observation\n * Layer 3 (detail) → Full observation content (~500-1000 tokens/result)\n */\n\nimport type { SearchOptions, IndexEntry, TimelineContext, MemorixDocument } from '../types.js';\nimport { searchObservations, getTimeline } from '../store/orama-store.js';\nimport { getObservation } from '../memory/observations.js';\nimport { formatIndexTable, formatTimeline, formatObservationDetail } from './index-format.js';\nimport { countTextTokens } from './token-budget.js';\n\n/**\n * Layer 1: Search and return a compact index.\n * Agent scans this to decide which observations to fetch in detail.\n */\nexport async function compactSearch(options: SearchOptions): Promise<{\n entries: IndexEntry[];\n formatted: string;\n totalTokens: number;\n}> {\n const entries = await searchObservations(options);\n const formatted = formatIndexTable(entries, options.query);\n const totalTokens = countTextTokens(formatted);\n\n return { entries, formatted, totalTokens };\n}\n\n/**\n * Layer 2: Get timeline context around an anchor observation.\n * Shows what happened before and after for temporal understanding.\n */\nexport async function compactTimeline(\n anchorId: number,\n projectId?: string,\n depthBefore = 3,\n depthAfter = 3,\n): Promise<{\n timeline: TimelineContext;\n formatted: string;\n totalTokens: number;\n}> {\n const result = await getTimeline(anchorId, projectId, depthBefore, depthAfter);\n\n const timeline: TimelineContext = {\n anchorId,\n anchorEntry: result.anchor,\n before: result.before,\n after: result.after,\n };\n\n const formatted = formatTimeline(timeline);\n const totalTokens = countTextTokens(formatted);\n\n return { timeline, formatted, totalTokens };\n}\n\n/**\n * Layer 3: Get full observation details by IDs.\n * Only called after the agent has filtered via L1/L2.\n */\nexport async function compactDetail(\n ids: number[],\n): Promise<{\n documents: MemorixDocument[];\n formatted: string;\n totalTokens: number;\n}> {\n // Use in-memory observations for reliable ID lookup (Orama where-clause\n // can be unreliable with empty term + number filter)\n const documents: MemorixDocument[] = [];\n for (const id of ids) {\n const obs = getObservation(id);\n if (obs) {\n documents.push({\n id: `obs-${obs.id}`,\n observationId: obs.id,\n entityName: obs.entityName,\n type: obs.type,\n title: obs.title,\n narrative: obs.narrative,\n facts: obs.facts.join('\\n'),\n filesModified: obs.filesModified.join('\\n'),\n concepts: obs.concepts.join(', '),\n tokens: obs.tokens,\n createdAt: obs.createdAt,\n projectId: obs.projectId,\n accessCount: 0,\n lastAccessedAt: '',\n status: obs.status ?? 'active',\n });\n }\n }\n\n const formattedParts = documents.map((doc: MemorixDocument) =>\n formatObservationDetail(doc),\n );\n\n const formatted = formattedParts.join('\\n\\n' + '═'.repeat(50) + '\\n\\n');\n const totalTokens = countTextTokens(formatted);\n\n return { documents, formatted, totalTokens };\n}\n","/**\n * Index Formatter\n *\n * Formats observation search results into the compact index table format.\n * Source: claude-mem's Progressive Disclosure index format.\n *\n * Output is a markdown table that agents can scan efficiently:\n * | ID | Time | T | Title | Tokens |\n * |-------|----------|----|--------------------------|--------|\n * | #42 | 2:14 PM | 🔴 | port 3001 conflict fix | ~155 |\n */\n\nimport type { IndexEntry, TimelineContext } from '../types.js';\n\n/**\n * Format a list of IndexEntries as a compact markdown table.\n * Grouped by date for readability (claude-mem pattern).\n */\nexport function formatIndexTable(entries: IndexEntry[], query?: string): string {\n if (entries.length === 0) {\n return query\n ? `No observations found matching \"${query}\".`\n : 'No observations found.';\n }\n\n const lines: string[] = [];\n\n if (query) {\n lines.push(`Found ${entries.length} observation(s) matching \"${query}\":\\n`);\n }\n\n lines.push('| ID | Time | T | Title | Tokens |');\n lines.push('|----|------|---|-------|--------|');\n\n // Check if any entry has matchedFields (explainable recall)\n const hasExplanation = entries.some(e => (e as unknown as Record<string, unknown>)['matchedFields']);\n\n if (hasExplanation) {\n lines.pop(); // remove previous header\n lines.pop();\n lines.push('| ID | Time | T | Title | Tokens | Matched |');\n lines.push('|----|------|---|-------|--------|---------|');\n }\n\n for (const entry of entries) {\n const matched = (entry as unknown as Record<string, unknown>)['matchedFields'] as string[] | undefined;\n if (hasExplanation && matched) {\n lines.push(\n `| #${entry.id} | ${entry.time} | ${entry.icon} | ${entry.title} | ~${entry.tokens} | ${matched.join(', ')} |`,\n );\n } else {\n lines.push(\n `| #${entry.id} | ${entry.time} | ${entry.icon} | ${entry.title} | ~${entry.tokens} |`,\n );\n }\n }\n\n lines.push('');\n lines.push(PROGRESSIVE_DISCLOSURE_HINT);\n\n return lines.join('\\n');\n}\n\n/**\n * Format a timeline context around an anchor observation.\n */\nexport function formatTimeline(timeline: TimelineContext): string {\n if (!timeline.anchorEntry) {\n return `Observation #${timeline.anchorId} not found.`;\n }\n\n const lines: string[] = [];\n lines.push(`Timeline around #${timeline.anchorId}:\\n`);\n\n if (timeline.before.length > 0) {\n lines.push('**Before:**');\n lines.push('| ID | Time | T | Title | Tokens |');\n lines.push('|----|------|---|-------|--------|');\n for (const entry of timeline.before) {\n lines.push(`| #${entry.id} | ${entry.time} | ${entry.icon} | ${entry.title} | ~${entry.tokens} |`);\n }\n lines.push('');\n }\n\n lines.push('**► Anchor:**');\n lines.push('| ID | Time | T | Title | Tokens |');\n lines.push('|----|------|---|-------|--------|');\n const a = timeline.anchorEntry;\n lines.push(`| #${a.id} | ${a.time} | ${a.icon} | ${a.title} | ~${a.tokens} |`);\n lines.push('');\n\n if (timeline.after.length > 0) {\n lines.push('**After:**');\n lines.push('| ID | Time | T | Title | Tokens |');\n lines.push('|----|------|---|-------|--------|');\n for (const entry of timeline.after) {\n lines.push(`| #${entry.id} | ${entry.time} | ${entry.icon} | ${entry.title} | ~${entry.tokens} |`);\n }\n lines.push('');\n }\n\n lines.push(PROGRESSIVE_DISCLOSURE_HINT);\n return lines.join('\\n');\n}\n\n/**\n * Format full observation details (Layer 3).\n * Adopted from claude-mem's observation detail format.\n */\nexport function formatObservationDetail(doc: {\n observationId: number;\n type: string;\n title: string;\n narrative: string;\n facts: string;\n filesModified: string;\n concepts: string;\n createdAt: string;\n projectId: string;\n entityName: string;\n}): string {\n const icon = getTypeIcon(doc.type);\n const lines: string[] = [];\n\n lines.push(`#${doc.observationId} ${icon} ${doc.title}`);\n lines.push('─'.repeat(50));\n lines.push(`Date: ${new Date(doc.createdAt).toLocaleString()}`);\n lines.push(`Type: ${doc.type}`);\n lines.push(`Entity: ${doc.entityName}`);\n lines.push(`Project: ${doc.projectId}`);\n lines.push('');\n lines.push(`Narrative: ${doc.narrative}`);\n\n const facts = doc.facts ? doc.facts.split('\\n').filter(Boolean) : [];\n if (facts.length > 0) {\n lines.push('');\n lines.push('Facts:');\n for (const fact of facts) {\n lines.push(`- ${fact}`);\n }\n }\n\n const files = doc.filesModified ? doc.filesModified.split('\\n').filter(Boolean) : [];\n if (files.length > 0) {\n lines.push('');\n lines.push('Files Modified:');\n for (const file of files) {\n lines.push(`- ${file}`);\n }\n }\n\n if (doc.concepts) {\n lines.push('');\n lines.push(`Concepts: ${doc.concepts}`);\n }\n\n return lines.join('\\n');\n}\n\n/** Icon lookup by observation type string */\nfunction getTypeIcon(type: string): string {\n const icons: Record<string, string> = {\n 'session-request': '🎯',\n 'gotcha': '🔴',\n 'problem-solution': '🟡',\n 'how-it-works': '🔵',\n 'what-changed': '🟢',\n 'discovery': '🟣',\n 'why-it-exists': '🟠',\n 'decision': '🟤',\n 'trade-off': '⚖️',\n };\n return icons[type] ?? '❓';\n}\n\n/**\n * Progressive Disclosure instruction hint.\n * Appended to L1/L2 results to teach the agent the workflow.\n */\nconst PROGRESSIVE_DISCLOSURE_HINT = `💡 **Progressive Disclosure:** This index shows WHAT exists and retrieval COST.\n- Use \\`memorix_detail\\` to fetch full observation details by ID\n- Use \\`memorix_timeline\\` to see chronological context around an observation\n- Critical types (🔴 gotcha, 🟤 decision, ⚖️ trade-off) are often worth fetching immediately`;\n","/**\n * Project Detector\n *\n * Identifies the current project using Git remote URL.\n * Source: shared-agent-memory's Git-based project isolation pattern.\n *\n * Extensible: fallback strategies can be added for non-git projects\n * (e.g., package.json name, directory name, etc.)\n */\n\nimport { execSync } from 'node:child_process';\nimport { existsSync, readFileSync } from 'node:fs';\nimport os from 'node:os';\nimport path from 'node:path';\nimport type { ProjectInfo } from '../types.js';\n\n/**\n * Detect the current project identity from Git remote or fallback.\n * @param cwd - Working directory to detect from (defaults to process.cwd())\n */\nexport function detectProject(cwd?: string): ProjectInfo {\n const basePath = cwd ?? process.cwd();\n // Priority: git root > package.json dir > CWD\n const rootPath = getGitRoot(basePath) ?? findPackageRoot(basePath) ?? basePath;\n const gitRemote = getGitRemote(rootPath);\n\n if (gitRemote) {\n const id = normalizeGitRemote(gitRemote);\n const name = id.split('/').pop() ?? path.basename(rootPath);\n return { id, name, gitRemote, rootPath };\n }\n\n // Validate the root before creating a fallback project.\n // Home dirs, system dirs, etc. get a \"placeholder\" prefix so data is still\n // persisted and tools are usable, but the user gets a warning to set a proper root.\n if (isDangerousRoot(rootPath)) {\n const name = path.basename(rootPath) || 'unknown';\n const id = `placeholder/${name}`;\n console.error(`[memorix] WARNING: cwd \"${rootPath}\" is not a project directory — using degraded mode (${id})`);\n console.error(`[memorix] For best results, set MEMORIX_PROJECT_ROOT or --cwd to your project path.`);\n return { id, name, rootPath };\n }\n\n // Fallback: use \"local/<dirname>\" — works for non-git and empty directories\n const name = path.basename(rootPath);\n const id = `local/${name}`;\n return { id, name, rootPath };\n}\n\n/**\n * Check whether a directory is a dangerous/invalid project root.\n * Returns TRUE for home directories, OS system directories,\n * drive roots, and IDE/tool configuration directories.\n * Returns FALSE for normal directories (including empty ones).\n */\nfunction isDangerousRoot(dirPath: string): boolean {\n const resolved = path.resolve(dirPath);\n const home = path.resolve(os.homedir());\n\n // Reject the home directory itself (e.g., C:\\Users\\Lenovo, /home/user)\n if (resolved === home) return true;\n\n // Reject drive roots (C:\\, D:\\, /)\n if (resolved === path.parse(resolved).root) return true;\n\n // Reject immediate children of home that are IDE/tool config dirs\n const basename = path.basename(resolved).toLowerCase();\n const knownNonProjectDirs = new Set([\n // IDE / editor config dirs\n '.vscode', '.cursor', '.windsurf', '.kiro', '.codex',\n '.gemini', '.claude', '.github', '.git',\n // OS / system dirs\n 'desktop', 'documents', 'downloads', 'pictures', 'videos', 'music',\n 'appdata', 'application data', 'library',\n // Package manager / tool dirs\n 'node_modules', '.npm', '.yarn', '.pnpm-store',\n '.config', '.local', '.cache', '.ssh', '.memorix',\n ]);\n if (knownNonProjectDirs.has(basename)) {\n const parent = path.resolve(path.dirname(resolved));\n // Only block if it's directly under home or a drive root\n if (parent === home || parent === path.parse(parent).root) {\n return true;\n }\n }\n\n return false;\n}\n\n/**\n * Walk up from cwd to find the nearest directory containing package.json.\n * Useful for non-git projects where the MCP server CWD may differ from project root.\n */\nfunction findPackageRoot(cwd: string): string | null {\n let dir = path.resolve(cwd);\n const root = path.parse(dir).root;\n while (dir !== root) {\n // Stop walking if we hit a dangerous directory (home dir, system dir)\n if (isDangerousRoot(dir)) return null;\n if (existsSync(path.join(dir, 'package.json'))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n return null;\n}\n\n/**\n * Get the Git repository root directory.\n * Returns null if not inside a git repository.\n */\nfunction getGitRoot(cwd: string): string | null {\n // Fast path: walk up to find .git directory (instant, no subprocess)\n let dir = path.resolve(cwd);\n const fsRoot = path.parse(dir).root;\n while (dir !== fsRoot) {\n if (existsSync(path.join(dir, '.git'))) return dir;\n dir = path.dirname(dir);\n }\n\n // Slow path: git CLI for edge cases (submodules, worktrees, bare repos)\n try {\n const root = execSync('git -c safe.directory=* rev-parse --show-toplevel', {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 5000,\n }).trim();\n return root || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Get the Git remote URL for the given directory.\n * Returns null if not a git repository or no remote configured.\n */\nfunction getGitRemote(cwd: string): string | null {\n // Fast path: read .git/config directly (instant, no subprocess)\n const fsRemote = readGitConfigRemote(cwd);\n if (fsRemote) return fsRemote;\n\n // Slow path: git CLI for edge cases (submodules, worktrees, non-standard layouts)\n try {\n const remote = execSync('git -c safe.directory=* remote get-url origin', {\n cwd,\n encoding: 'utf-8',\n stdio: ['pipe', 'pipe', 'pipe'],\n timeout: 5000,\n }).trim();\n return remote || null;\n } catch {\n return null;\n }\n}\n\n/**\n * Fallback: parse remote.origin.url from .git/config when git CLI fails.\n * Handles Windows \"dubious ownership\" and other permission issues.\n */\nfunction readGitConfigRemote(cwd: string): string | null {\n try {\n const configPath = path.join(cwd, '.git', 'config');\n if (!existsSync(configPath)) return null;\n const content = readFileSync(configPath, 'utf-8');\n // Parse INI-style: [remote \"origin\"] section, url = ...\n const remoteMatch = content.match(/\\[remote\\s+\"origin\"\\]([\\s\\S]*?)(?=\\n\\[|$)/);\n if (!remoteMatch) return null;\n const urlMatch = remoteMatch[1].match(/^\\s*url\\s*=\\s*(.+)$/m);\n return urlMatch ? urlMatch[1].trim() : null;\n } catch {\n return null;\n }\n}\n\n/**\n * Normalize a Git remote URL to a consistent project ID.\n *\n * Examples:\n * https://github.com/user/repo.git → user/repo\n * git@github.com:user/repo.git → user/repo\n * ssh://git@github.com/user/repo → user/repo\n */\nfunction normalizeGitRemote(remote: string): string {\n let normalized = remote;\n\n // Remove trailing .git\n normalized = normalized.replace(/\\.git$/, '');\n\n // Handle SSH format: git@github.com:user/repo\n const sshMatch = normalized.match(/^[\\w-]+@[\\w.-]+:(.+)$/);\n if (sshMatch) {\n return sshMatch[1];\n }\n\n // Handle HTTPS/SSH URL format\n try {\n const url = new URL(normalized);\n // Remove leading slash\n return url.pathname.replace(/^\\//, '');\n } catch {\n // If URL parsing fails, take last two segments\n const segments = normalized.split('/').filter(Boolean);\n return segments.slice(-2).join('/');\n }\n}\n","/**\n * Rules Syncer\n *\n * Core sync engine for cross-agent rule synchronization.\n * Scans project for rule files from all supported agents,\n * deduplicates by content hash, detects conflicts, and\n * generates output in any target agent format.\n *\n * This is the ~15% original logic in Memorix — dedup and\n * conflict detection are not found in any existing tool.\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { UnifiedRule, RuleSource, RuleFormatAdapter } from '../types.js';\nimport { CursorAdapter } from './adapters/cursor.js';\nimport { ClaudeCodeAdapter } from './adapters/claude-code.js';\nimport { CodexAdapter } from './adapters/codex.js';\nimport { WindsurfAdapter } from './adapters/windsurf.js';\nimport { AntigravityAdapter } from './adapters/antigravity.js';\nimport { CopilotAdapter } from './adapters/copilot.js';\nimport { KiroAdapter } from './adapters/kiro.js';\nimport { TraeAdapter } from './adapters/trae.js';\n\n/** A detected conflict between two rules */\nexport interface RuleConflict {\n ruleA: UnifiedRule;\n ruleB: UnifiedRule;\n reason: string;\n}\n\n/** Sync status report */\nexport interface SyncStatus {\n totalRules: number;\n uniqueRules: number;\n sources: RuleSource[];\n conflicts: RuleConflict[];\n}\n\n/** File scan patterns for each adapter */\ninterface ScanEntry {\n adapter: RuleFormatAdapter;\n paths: string[];\n}\n\nexport class RulesSyncer {\n private readonly projectRoot: string;\n private readonly adapters: Map<RuleSource, RuleFormatAdapter>;\n\n constructor(projectRoot: string) {\n this.projectRoot = projectRoot;\n this.adapters = new Map();\n\n const all: RuleFormatAdapter[] = [\n new CursorAdapter(),\n new ClaudeCodeAdapter(),\n new CodexAdapter(),\n new WindsurfAdapter(),\n new AntigravityAdapter(),\n new CopilotAdapter(),\n new KiroAdapter(),\n new TraeAdapter(),\n ];\n for (const a of all) {\n this.adapters.set(a.source, a);\n }\n }\n\n /** Scan the project root for all known rule files and parse them */\n async scanRules(): Promise<UnifiedRule[]> {\n const rules: UnifiedRule[] = [];\n\n const scanEntries = this.buildScanEntries();\n\n for (const entry of scanEntries) {\n for (const scanPath of entry.paths) {\n const found = await this.findFiles(scanPath);\n for (const filePath of found) {\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n const relativePath = path.relative(this.projectRoot, filePath).replace(/\\\\/g, '/');\n const parsed = entry.adapter.parse(relativePath, content);\n rules.push(...parsed);\n } catch {\n // Skip unreadable files\n }\n }\n }\n }\n\n return rules;\n }\n\n /** Remove duplicate rules by content hash, keeping highest priority */\n deduplicateRules(rules: UnifiedRule[]): UnifiedRule[] {\n const byHash = new Map<string, UnifiedRule>();\n\n for (const rule of rules) {\n const existing = byHash.get(rule.hash);\n if (!existing || rule.priority > existing.priority) {\n byHash.set(rule.hash, rule);\n }\n }\n\n return Array.from(byHash.values());\n }\n\n /** Detect conflicts: rules with overlapping paths but different content */\n detectConflicts(rules: UnifiedRule[]): RuleConflict[] {\n const conflicts: RuleConflict[] = [];\n\n for (let i = 0; i < rules.length; i++) {\n for (let j = i + 1; j < rules.length; j++) {\n const a = rules[i];\n const b = rules[j];\n\n // Only compare rules from different sources\n if (a.source === b.source) continue;\n // Only compare if both have overlapping paths\n if (a.scope === 'path-specific' && b.scope === 'path-specific') {\n if (this.pathsOverlap(a.paths || [], b.paths || [])) {\n conflicts.push({\n ruleA: a,\n ruleB: b,\n reason: `Overlapping paths: ${a.source} vs ${b.source}`,\n });\n }\n }\n }\n }\n\n return conflicts;\n }\n\n /** Generate rule files for a target agent format */\n generateForTarget(\n rules: UnifiedRule[],\n target: RuleSource,\n ): { filePath: string; content: string }[] {\n const adapter = this.adapters.get(target);\n if (!adapter) {\n throw new Error(`No adapter for target: ${target}`);\n }\n return adapter.generate(rules);\n }\n\n /** Get a full sync status report */\n async syncStatus(): Promise<SyncStatus> {\n const rules = await this.scanRules();\n const deduped = this.deduplicateRules(rules);\n const conflicts = this.detectConflicts(deduped);\n const sources = [...new Set(rules.map(r => r.source))];\n\n return {\n totalRules: rules.length,\n uniqueRules: deduped.length,\n sources,\n conflicts,\n };\n }\n\n /** Build scan entries mapping adapters to their file search paths */\n private buildScanEntries(): ScanEntry[] {\n const entries: ScanEntry[] = [];\n\n for (const adapter of this.adapters.values()) {\n const absolutePaths = adapter.filePatterns.map(p =>\n path.join(this.projectRoot, p),\n );\n entries.push({ adapter, paths: absolutePaths });\n }\n\n return entries;\n }\n\n /** Find files matching a glob-like path (simple implementation) */\n private async findFiles(pattern: string): Promise<string[]> {\n const dir = path.dirname(pattern);\n const fileGlob = path.basename(pattern);\n\n try {\n const stat = await fs.stat(dir);\n if (!stat.isDirectory()) {\n // It's a direct file path\n try {\n await fs.access(pattern);\n return [pattern];\n } catch {\n return [];\n }\n }\n } catch {\n // If dir doesn't exist, check if pattern itself is a file\n try {\n await fs.access(pattern);\n return [pattern];\n } catch {\n return [];\n }\n }\n\n // If it's a glob pattern (contains *), list dir and filter\n if (fileGlob.includes('*')) {\n try {\n const files = await fs.readdir(dir);\n const ext = fileGlob.replace('*', '');\n return files\n .filter(f => ext ? f.endsWith(ext) : true)\n .map(f => path.join(dir, f));\n } catch {\n return [];\n }\n }\n\n // Direct file\n try {\n await fs.access(path.join(dir, fileGlob));\n return [path.join(dir, fileGlob)];\n } catch {\n return [];\n }\n }\n\n /** Check if two sets of glob paths overlap (simplified: exact match) */\n private pathsOverlap(a: string[], b: string[]): boolean {\n for (const pa of a) {\n for (const pb of b) {\n if (pa === pb) return true;\n }\n }\n return false;\n }\n}\n","/**\n * Cursor Rule Format Adapter\n *\n * Parses and generates rules in Cursor's formats:\n * - .cursor/rules/*.mdc (Markdown + frontmatter with description, alwaysApply, globs)\n * - .cursorrules (legacy plain text)\n * - AGENTS.md (pure Markdown)\n *\n * Source: Cursor official documentation on Project Rules.\n */\n\nimport matter from 'gray-matter';\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class CursorAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'cursor';\n\n readonly filePatterns = [\n '.cursor/rules/*.mdc',\n '.cursorrules',\n 'AGENTS.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n if (filePath.endsWith('.mdc')) {\n return this.parseMdc(filePath, content);\n }\n if (filePath === '.cursorrules' || filePath.endsWith('/.cursorrules')) {\n return this.parseLegacy(filePath, content);\n }\n if (filePath.endsWith('AGENTS.md')) {\n return this.parseAgentsMd(filePath, content);\n }\n return [];\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n return rules.map((rule, i) => {\n const fm: Record<string, unknown> = {};\n if (rule.description) fm.description = rule.description;\n if (rule.alwaysApply !== undefined) fm.alwaysApply = rule.alwaysApply;\n if (rule.paths && rule.paths.length > 0) fm.globs = rule.paths;\n\n const fileName = rule.id\n .replace(/^cursor:/, '')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n || `rule-${i}`;\n\n const body = Object.keys(fm).length > 0\n ? matter.stringify(rule.content, fm)\n : rule.content;\n\n return {\n filePath: `.cursor/rules/${fileName}.mdc`,\n content: body,\n };\n });\n }\n\n private parseMdc(filePath: string, content: string): UnifiedRule[] {\n const { data, content: body } = matter(content);\n const trimmed = body.trim();\n if (!trimmed) return [];\n\n const globs = data.globs as string[] | undefined;\n const hasGlobs = Array.isArray(globs) && globs.length > 0;\n const alwaysApply = data.alwaysApply === true;\n\n let scope: UnifiedRule['scope'] = 'project';\n if (alwaysApply) scope = 'global';\n else if (hasGlobs) scope = 'path-specific';\n\n return [{\n id: generateRuleId('cursor', filePath),\n content: trimmed,\n description: data.description as string | undefined,\n source: 'cursor',\n scope,\n paths: hasGlobs ? globs : undefined,\n alwaysApply,\n priority: alwaysApply ? 10 : 5,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseLegacy(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('cursor', filePath),\n content: trimmed,\n source: 'cursor',\n scope: 'project',\n priority: 3,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseAgentsMd(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('cursor', filePath),\n content: trimmed,\n source: 'cursor',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n}\n","/**\n * Rules Utilities\n *\n * Shared helpers for rule parsing: content hashing, ID generation, etc.\n */\n\nimport { createHash } from 'node:crypto';\n\n/** Generate a deterministic content hash for deduplication */\nexport function hashContent(content: string): string {\n return createHash('sha256')\n .update(content.trim())\n .digest('hex')\n .substring(0, 16);\n}\n\n/** Generate a rule ID from source + file path */\nexport function generateRuleId(source: string, filePath: string): string {\n const sanitized = filePath.replace(/[\\/\\\\]/g, '-').replace(/^\\./, '');\n return `${source}:${sanitized}`;\n}\n","/**\n * Claude Code Rule Format Adapter\n *\n * Parses and generates rules in Claude Code's formats:\n * - CLAUDE.md / .claude/CLAUDE.md (project-level Markdown)\n * - .claude/rules/*.md (Markdown with optional `paths` frontmatter)\n *\n * Source: Claude Code official documentation.\n */\n\nimport matter from 'gray-matter';\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class ClaudeCodeAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'claude-code';\n\n readonly filePatterns = [\n 'CLAUDE.md',\n '.claude/CLAUDE.md',\n '.claude/rules/*.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n // .claude/rules/*.md may have `paths` frontmatter\n if (filePath.includes('.claude/rules/')) {\n return this.parseModularRule(filePath, content);\n }\n // CLAUDE.md — project-level\n return this.parseClaudeMd(filePath, content);\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n const projectRules = rules.filter(r => r.scope !== 'path-specific');\n const pathRules = rules.filter(r => r.scope === 'path-specific');\n\n const files: { filePath: string; content: string }[] = [];\n\n if (projectRules.length > 0) {\n files.push({\n filePath: 'CLAUDE.md',\n content: projectRules.map(r => r.content).join('\\n\\n'),\n });\n }\n\n for (const rule of pathRules) {\n const fm: Record<string, unknown> = {};\n if (rule.paths && rule.paths.length > 0) fm.paths = rule.paths;\n\n const fileName = rule.id\n .replace(/^claude-code:/, '')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n || 'rule';\n\n files.push({\n filePath: `.claude/rules/${fileName}.md`,\n content: Object.keys(fm).length > 0\n ? matter.stringify(rule.content, fm)\n : rule.content,\n });\n }\n\n return files;\n }\n\n private parseClaudeMd(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('claude-code', filePath),\n content: trimmed,\n source: 'claude-code',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseModularRule(filePath: string, content: string): UnifiedRule[] {\n const { data, content: body } = matter(content);\n const trimmed = body.trim();\n if (!trimmed) return [];\n\n const paths = data.paths as string[] | undefined;\n const hasPaths = Array.isArray(paths) && paths.length > 0;\n\n return [{\n id: generateRuleId('claude-code', filePath),\n content: trimmed,\n description: data.description as string | undefined,\n source: 'claude-code',\n scope: hasPaths ? 'path-specific' : 'project',\n paths: hasPaths ? paths : undefined,\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n}\n","/**\n * OpenAI Codex Rule Format Adapter\n *\n * Parses and generates rules in Codex's formats:\n * - .agents/skills/[name]/SKILL.md (Markdown + frontmatter with name, description)\n * - AGENTS.md (pure Markdown)\n *\n * Source: OpenAI Codex Skills documentation.\n */\n\nimport matter from 'gray-matter';\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class CodexAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'codex';\n\n readonly filePatterns = [\n '.agents/skills/*/SKILL.md',\n 'AGENTS.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n if (filePath.includes('SKILL.md')) {\n return this.parseSkillMd(filePath, content);\n }\n if (filePath.endsWith('AGENTS.md')) {\n return this.parseAgentsMd(filePath, content);\n }\n return [];\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n return rules.map((rule, i) => {\n const skillName = rule.id\n .replace(/^codex:/, '')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n || `skill-${i}`;\n\n const fm: Record<string, unknown> = {\n name: skillName,\n };\n\n // Codex needs description to know WHEN to trigger the skill.\n // If no description exists, auto-generate from content (first 120 chars).\n if (rule.description) {\n fm.description = rule.description;\n } else {\n fm.description = this.autoDescription(rule.content);\n }\n\n return {\n filePath: `.agents/skills/${skillName}/SKILL.md`,\n content: matter.stringify(rule.content, fm),\n };\n });\n }\n\n /** Extract a short description from rule content for Codex skill triggering */\n private autoDescription(content: string): string {\n // Take first meaningful line, strip markdown formatting\n const lines = content.split('\\n').map(l => l.trim()).filter(Boolean);\n const first = lines[0]?.replace(/^#+\\s*/, '').replace(/^[-*]\\s*/, '') || 'Project rules';\n if (first.length <= 120) return first;\n return first.substring(0, 117) + '...';\n }\n\n private parseSkillMd(filePath: string, content: string): UnifiedRule[] {\n const { data, content: body } = matter(content);\n const trimmed = body.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('codex', filePath),\n content: trimmed,\n description: (data.description as string) || undefined,\n source: 'codex',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseAgentsMd(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('codex', filePath),\n content: trimmed,\n source: 'codex',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n}\n","/**\n * Windsurf Rule Format Adapter\n *\n * Parses and generates rules in Windsurf's formats:\n * - .windsurfrules (legacy plain text)\n * - .windsurf/rules/*.md (Markdown with optional frontmatter)\n *\n * Source: Windsurf/Codeium documentation.\n */\n\nimport matter from 'gray-matter';\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class WindsurfAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'windsurf';\n\n readonly filePatterns = [\n '.windsurfrules',\n '.windsurf/rules/*.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n if (filePath === '.windsurfrules' || filePath.endsWith('/.windsurfrules')) {\n return this.parseLegacy(filePath, content);\n }\n if (filePath.includes('.windsurf/rules/')) {\n return this.parseModularRule(filePath, content);\n }\n return [];\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n return rules.map((rule, i) => {\n const fm: Record<string, unknown> = {};\n if (rule.description) fm.description = rule.description;\n\n const fileName = rule.id\n .replace(/^windsurf:/, '')\n .replace(/[^a-zA-Z0-9-_]/g, '-')\n || `rule-${i}`;\n\n const body = Object.keys(fm).length > 0\n ? matter.stringify(rule.content, fm)\n : rule.content;\n\n return {\n filePath: `.windsurf/rules/${fileName}.md`,\n content: body,\n };\n });\n }\n\n private parseLegacy(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('windsurf', filePath),\n content: trimmed,\n source: 'windsurf',\n scope: 'project',\n priority: 3,\n hash: hashContent(trimmed),\n }];\n }\n\n private parseModularRule(filePath: string, content: string): UnifiedRule[] {\n const { data, content: body } = matter(content);\n const trimmed = body.trim();\n if (!trimmed) return [];\n\n return [{\n id: generateRuleId('windsurf', filePath),\n content: trimmed,\n description: data.description as string | undefined,\n source: 'windsurf',\n scope: 'project',\n priority: 5,\n hash: hashContent(trimmed),\n }];\n }\n}\n","/**\r\n * Antigravity IDE Rule Format Adapter\r\n *\r\n * Parses and generates rules in Antigravity's formats:\r\n * - GEMINI.md (global rules, similar to CLAUDE.md)\r\n * - .agent/rules/*.md (workspace rules, Markdown with optional frontmatter)\r\n * - .agent/skills/[name]/SKILL.md (skills, Markdown + YAML frontmatter)\r\n *\r\n * Source: Antigravity official documentation (https://antigravity.google/docs/agent/rules)\r\n *\r\n * Note: Antigravity is Google's agent-first IDE, a VS Code fork.\r\n * Global rules: ~/.gemini/GEMINI.md\r\n * Workspace rules: <project>/.agent/rules/*.md\r\n * Skills: <project>/.agent/skills/[name]/SKILL.md\r\n * Workflows: <project>/.agent/workflows/*.md\r\n */\r\n\r\nimport matter from 'gray-matter';\r\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\r\nimport { hashContent, generateRuleId } from '../utils.js';\r\n\r\nexport class AntigravityAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'antigravity';\r\n\r\n readonly filePatterns = [\r\n 'GEMINI.md',\r\n '.agent/rules/*.md',\r\n '.agent/skills/*/SKILL.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n // .agent/skills/*/SKILL.md — skill files with frontmatter\r\n if (filePath.includes('SKILL.md')) {\r\n return this.parseSkillMd(filePath, content);\r\n }\r\n // .agent/rules/*.md — workspace rules\r\n if (filePath.includes('.agent/rules/')) {\r\n return this.parseAgentRule(filePath, content);\r\n }\r\n // GEMINI.md — global project-level rules\r\n if (filePath === 'GEMINI.md' || filePath.endsWith('/GEMINI.md')) {\r\n return this.parseGeminiMd(filePath, content);\r\n }\r\n return [];\r\n }\r\n\r\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\r\n const projectRules = rules.filter(r => r.scope !== 'path-specific');\r\n const pathRules = rules.filter(r => r.scope === 'path-specific');\r\n\r\n const files: { filePath: string; content: string }[] = [];\r\n\r\n // Generate workspace rules as .agent/rules/*.md\r\n for (const rule of [...projectRules, ...pathRules]) {\r\n const fm: Record<string, unknown> = {};\r\n if (rule.description) fm.description = rule.description;\r\n\r\n const fileName = rule.id\r\n .replace(/^antigravity:/, '')\r\n .replace(/[^a-zA-Z0-9-_]/g, '-')\r\n || 'rule';\r\n\r\n const body = Object.keys(fm).length > 0\r\n ? matter.stringify(rule.content, fm)\r\n : rule.content;\r\n\r\n files.push({\r\n filePath: `.agent/rules/${fileName}.md`,\r\n content: body,\r\n });\r\n }\r\n\r\n return files;\r\n }\r\n\r\n private parseGeminiMd(filePath: string, content: string): UnifiedRule[] {\r\n const trimmed = content.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('antigravity', filePath),\r\n content: trimmed,\r\n source: 'antigravity',\r\n scope: 'global',\r\n priority: 10,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseAgentRule(filePath: string, content: string): UnifiedRule[] {\r\n const { data, content: body } = matter(content);\r\n const trimmed = body.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('antigravity', filePath),\r\n content: trimmed,\r\n description: data.description as string | undefined,\r\n source: 'antigravity',\r\n scope: 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseSkillMd(filePath: string, content: string): UnifiedRule[] {\r\n const { data, content: body } = matter(content);\r\n const trimmed = body.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('antigravity', filePath),\r\n content: trimmed,\r\n description: (data.description as string) || undefined,\r\n source: 'antigravity',\r\n scope: 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n}\r\n","/**\r\n * GitHub Copilot Rule Format Adapter\r\n *\r\n * Parses and generates rules in Copilot's formats:\r\n * - .github/copilot-instructions.md (repository-wide instructions, plain Markdown)\r\n * - .github/instructions/*.instructions.md (path-specific, YAML frontmatter with `applyTo` glob)\r\n *\r\n * Source: https://docs.github.com/en/copilot/customizing-copilot/adding-repository-custom-instructions-for-github-copilot\r\n */\r\n\r\nimport matter from 'gray-matter';\r\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\r\nimport { hashContent, generateRuleId } from '../utils.js';\r\n\r\nexport class CopilotAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'copilot';\r\n\r\n readonly filePatterns = [\r\n '.github/copilot-instructions.md',\r\n '.github/instructions/*.instructions.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n // Path-specific instruction files (.github/instructions/*.instructions.md)\r\n if (filePath.includes('.instructions.md') && filePath.includes('.github/instructions')) {\r\n return this.parsePathSpecific(filePath, content);\r\n }\r\n // Repository-wide instructions (.github/copilot-instructions.md)\r\n if (filePath.includes('copilot-instructions.md')) {\r\n return this.parseRepoWide(filePath, content);\r\n }\r\n return [];\r\n }\r\n\r\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\r\n // If only one rule with no path-specific globs, output as copilot-instructions.md\r\n if (rules.length === 1 && (!rules[0].paths || rules[0].paths.length === 0)) {\r\n return [{\r\n filePath: '.github/copilot-instructions.md',\r\n content: rules[0].content,\r\n }];\r\n }\r\n\r\n // Multiple rules → output as path-specific instruction files\r\n return rules.map((rule, i) => {\r\n const fm: Record<string, unknown> = {};\r\n\r\n // Preserve applyTo if available\r\n if (rule.paths && rule.paths.length > 0) {\r\n fm.applyTo = rule.paths.join(',');\r\n }\r\n if (rule.description) {\r\n fm.description = rule.description;\r\n }\r\n\r\n const fileName = rule.id\r\n .replace(/^copilot:/, '')\r\n .replace(/[^a-zA-Z0-9-_]/g, '-')\r\n || `instruction-${i}`;\r\n\r\n const body = Object.keys(fm).length > 0\r\n ? matter.stringify(rule.content, fm)\r\n : rule.content;\r\n\r\n return {\r\n filePath: `.github/instructions/${fileName}.instructions.md`,\r\n content: body,\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * Parse repository-wide .github/copilot-instructions.md\r\n * This is plain Markdown with no frontmatter.\r\n */\r\n private parseRepoWide(filePath: string, content: string): UnifiedRule[] {\r\n const trimmed = content.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('copilot', filePath),\r\n content: trimmed,\r\n description: 'Repository-wide Copilot instructions',\r\n source: 'copilot',\r\n scope: 'project',\r\n priority: 3,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n /**\r\n * Parse path-specific .github/instructions/*.instructions.md\r\n * These have YAML frontmatter with `applyTo` glob pattern(s).\r\n */\r\n private parsePathSpecific(filePath: string, content: string): UnifiedRule[] {\r\n const { data, content: body } = matter(content);\r\n const trimmed = body.trim();\r\n if (!trimmed) return [];\r\n\r\n const applyTo = data.applyTo as string | undefined;\r\n const hasApplyTo = !!applyTo;\r\n\r\n const rule: UnifiedRule = {\r\n id: generateRuleId('copilot', filePath),\r\n content: trimmed,\r\n source: 'copilot',\r\n scope: hasApplyTo ? 'path-specific' : 'project',\r\n priority: 5,\r\n hash: hashContent(trimmed),\r\n };\r\n\r\n // Extract applyTo glob pattern(s) → store in paths[]\r\n if (hasApplyTo) {\r\n rule.paths = applyTo!.split(',').map(p => p.trim());\r\n }\r\n\r\n // Extract description if present\r\n if (data.description) {\r\n rule.description = data.description as string;\r\n }\r\n\r\n return [rule];\r\n }\r\n}\r\n","/**\r\n * Kiro Rule Format Adapter\r\n *\r\n * Parses and generates rules in Kiro's formats:\r\n * - .kiro/steering/*.md (Markdown steering rules with optional frontmatter)\r\n * - AGENTS.md (always included, pure Markdown)\r\n *\r\n * Source: Kiro official documentation on Steering Rules.\r\n * https://kiro.dev/docs/steering/\r\n *\r\n * Kiro uses \".kiro/steering/\" for project-level rules\r\n * and \"~/.kiro/steering/\" for user-level (global) rules.\r\n *\r\n * Frontmatter inclusion modes:\r\n * - always (default): loaded into every interaction\r\n * - fileMatch + fileMatchPattern: conditional on file globs\r\n * - manual: on-demand via #name in chat\r\n * - auto + name + description: auto-included when relevant\r\n */\r\n\r\nimport matter from 'gray-matter';\r\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\r\nimport { hashContent, generateRuleId } from '../utils.js';\r\n\r\n/** Kiro inclusion mode values */\r\ntype KiroInclusion = 'always' | 'fileMatch' | 'manual' | 'auto';\r\n\r\nexport class KiroAdapter implements RuleFormatAdapter {\r\n readonly source: RuleSource = 'kiro';\r\n\r\n readonly filePatterns = [\r\n '.kiro/steering/*.md',\r\n 'AGENTS.md',\r\n ];\r\n\r\n parse(filePath: string, content: string): UnifiedRule[] {\r\n if (filePath.includes('.kiro/steering/')) {\r\n return this.parseSteeringRule(filePath, content);\r\n }\r\n if (filePath.endsWith('AGENTS.md')) {\r\n return this.parseAgentsMd(filePath, content);\r\n }\r\n return [];\r\n }\r\n\r\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\r\n return rules.map((rule, i) => {\r\n const fm: Record<string, unknown> = {};\r\n if (rule.description) fm.description = rule.description;\r\n\r\n // Map unified scope → Kiro inclusion mode\r\n if (rule.paths && rule.paths.length > 0) {\r\n fm.inclusion = 'fileMatch';\r\n fm.fileMatchPattern = rule.paths.length === 1\r\n ? rule.paths[0]\r\n : rule.paths;\r\n } else if (rule.alwaysApply) {\r\n fm.inclusion = 'always';\r\n }\r\n\r\n const fileName = rule.id\r\n .replace(/^kiro:/, '')\r\n .replace(/[^a-zA-Z0-9-_]/g, '-')\r\n || `rule-${i}`;\r\n\r\n const body = Object.keys(fm).length > 0\r\n ? matter.stringify(rule.content, fm)\r\n : rule.content;\r\n\r\n return {\r\n filePath: `.kiro/steering/${fileName}.md`,\r\n content: body,\r\n };\r\n });\r\n }\r\n\r\n private parseSteeringRule(filePath: string, content: string): UnifiedRule[] {\r\n const { data, content: body } = matter(content);\r\n const trimmed = body.trim();\r\n if (!trimmed) return [];\r\n\r\n // Kiro uses \"inclusion\" field: always | fileMatch | manual | auto\r\n const inclusion = (data.inclusion as KiroInclusion | undefined) ?? 'always';\r\n const alwaysApply = inclusion === 'always' || inclusion === 'auto';\r\n\r\n // fileMatchPattern can be a string or string[]\r\n let paths: string[] | undefined;\r\n if (inclusion === 'fileMatch' && data.fileMatchPattern) {\r\n paths = Array.isArray(data.fileMatchPattern)\r\n ? data.fileMatchPattern\r\n : [data.fileMatchPattern];\r\n }\r\n\r\n let scope: UnifiedRule['scope'] = 'project';\r\n if (alwaysApply) scope = 'global';\r\n else if (paths && paths.length > 0) scope = 'path-specific';\r\n\r\n return [{\r\n id: generateRuleId('kiro', filePath),\r\n content: trimmed,\r\n description: data.description as string | undefined,\r\n source: 'kiro',\r\n scope,\r\n paths,\r\n alwaysApply,\r\n priority: alwaysApply ? 10 : 5,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n\r\n private parseAgentsMd(filePath: string, content: string): UnifiedRule[] {\r\n const trimmed = content.trim();\r\n if (!trimmed) return [];\r\n\r\n return [{\r\n id: generateRuleId('kiro', filePath),\r\n content: trimmed,\r\n source: 'kiro',\r\n scope: 'project',\r\n alwaysApply: true,\r\n priority: 10,\r\n hash: hashContent(trimmed),\r\n }];\r\n }\r\n}\r\n\r\n","/**\n * Trae IDE Rule Format Adapter\n *\n * Parses and generates rules in Trae's format:\n * - .trae/rules/project_rules.md (project-level rules, plain Markdown)\n *\n * Trae also supports user-level rules (user_rules.md) created via the UI,\n * but those are managed by Trae itself and not project-scoped.\n *\n * Rules are plain Markdown — no frontmatter, no special syntax.\n * Project rules override personal rules when there are conflicts.\n *\n * Source: https://docs.trae.ai/ide/rules\n */\n\nimport type { RuleFormatAdapter, UnifiedRule, RuleSource } from '../../types.js';\nimport { hashContent, generateRuleId } from '../utils.js';\n\nexport class TraeAdapter implements RuleFormatAdapter {\n readonly source: RuleSource = 'trae';\n\n readonly filePatterns = [\n '.trae/rules/project_rules.md',\n '.trae/rules/*.md',\n ];\n\n parse(filePath: string, content: string): UnifiedRule[] {\n const trimmed = content.trim();\n if (!trimmed) return [];\n\n const isProjectRules = filePath.includes('project_rules.md');\n\n return [{\n id: generateRuleId('trae', filePath),\n content: trimmed,\n description: isProjectRules ? 'Trae project rules' : undefined,\n source: 'trae',\n scope: 'project',\n alwaysApply: true,\n priority: isProjectRules ? 10 : 5,\n hash: hashContent(trimmed),\n }];\n }\n\n generate(rules: UnifiedRule[]): { filePath: string; content: string }[] {\n if (rules.length === 0) return [];\n\n // Trae uses a single project_rules.md file — merge all rules into one\n const combined = rules.map(r => r.content).join('\\n\\n---\\n\\n');\n\n return [{\n filePath: '.trae/rules/project_rules.md',\n content: combined,\n }];\n }\n}\n","import { readFileSync, readdirSync, existsSync, cpSync, mkdirSync } from 'node:fs';\nimport { join, basename } from 'node:path';\nimport { homedir } from 'node:os';\nimport type {\n AgentTarget,\n MCPServerEntry,\n MCPConfigAdapter,\n WorkflowEntry,\n WorkspaceSyncResult,\n RuleSource,\n SkillEntry,\n SkillConflict,\n} from '../types.js';\nimport { WindsurfMCPAdapter } from './mcp-adapters/windsurf.js';\nimport { CursorMCPAdapter } from './mcp-adapters/cursor.js';\nimport { CodexMCPAdapter } from './mcp-adapters/codex.js';\nimport { ClaudeCodeMCPAdapter } from './mcp-adapters/claude-code.js';\nimport { CopilotMCPAdapter } from './mcp-adapters/copilot.js';\nimport { AntigravityMCPAdapter } from './mcp-adapters/antigravity.js';\nimport { KiroMCPAdapter } from './mcp-adapters/kiro.js';\nimport { OpenCodeMCPAdapter } from './mcp-adapters/opencode.js';\nimport { TraeMCPAdapter } from './mcp-adapters/trae.js';\nimport { WorkflowSyncer } from './workflow-sync.js';\nimport { RulesSyncer } from '../rules/syncer.js';\nimport { sanitize } from './sanitizer.js';\nimport { WorkspaceSyncApplier, type ApplyResult } from './applier.js';\n\n/** Scan result from workspace analysis */\nexport interface WorkspaceScanResult {\n mcpConfigs: Record<AgentTarget, MCPServerEntry[]>;\n workflows: WorkflowEntry[];\n rulesCount: number;\n skills: SkillEntry[];\n skillConflicts: SkillConflict[];\n}\n\n/**\n * WorkspaceSyncEngine — orchestrates cross-agent workspace migration.\n *\n * Capabilities:\n * 1. MCP config sync (JSON ↔ TOML across 4 agents)\n * 2. Workflow sync (Windsurf workflows → Codex skills / Cursor rules / CLAUDE.md)\n * 3. Rules sync (via existing RulesSyncer)\n */\nexport class WorkspaceSyncEngine {\n private adapters: Map<AgentTarget, MCPConfigAdapter>;\n private workflowSyncer: WorkflowSyncer;\n private rulesSyncer: RulesSyncer;\n\n constructor(private projectRoot: string) {\n this.adapters = new Map<AgentTarget, MCPConfigAdapter>([\n ['windsurf', new WindsurfMCPAdapter()],\n ['cursor', new CursorMCPAdapter()],\n ['codex', new CodexMCPAdapter()],\n ['claude-code', new ClaudeCodeMCPAdapter()],\n ['copilot', new CopilotMCPAdapter()],\n ['antigravity', new AntigravityMCPAdapter()],\n ['kiro', new KiroMCPAdapter()],\n ['opencode', new OpenCodeMCPAdapter()],\n ['trae', new TraeMCPAdapter()],\n ]);\n this.workflowSyncer = new WorkflowSyncer();\n this.rulesSyncer = new RulesSyncer(projectRoot);\n }\n\n /**\n * Scan the workspace for all agent configs, workflows, and rules.\n */\n async scan(): Promise<WorkspaceScanResult> {\n const mcpConfigs: Record<AgentTarget, MCPServerEntry[]> = {\n windsurf: [],\n cursor: [],\n codex: [],\n 'claude-code': [],\n copilot: [],\n antigravity: [],\n kiro: [],\n opencode: [],\n trae: [],\n };\n\n // Scan MCP configs from each agent (merge all paths, dedup by name)\n for (const [target, adapter] of this.adapters) {\n const configPath = adapter.getConfigPath(this.projectRoot);\n const globalPath = adapter.getConfigPath();\n\n const pathsToCheck = [configPath, globalPath];\n\n // Antigravity has an additional config at ~/.gemini/antigravity/mcp_config.json\n if (target === 'antigravity') {\n pathsToCheck.push(join(homedir(), '.gemini', 'antigravity', 'mcp_config.json'));\n }\n\n const merged = new Map<string, MCPServerEntry>();\n for (const path of pathsToCheck) {\n if (existsSync(path)) {\n try {\n const content = readFileSync(path, 'utf-8');\n const servers = adapter.parse(content);\n for (const s of servers) {\n if (!merged.has(s.name)) merged.set(s.name, s);\n }\n } catch {\n // Skip unreadable configs\n }\n }\n }\n if (merged.size > 0) {\n mcpConfigs[target] = Array.from(merged.values());\n }\n }\n\n // Scan Windsurf workflows\n const workflows = this.scanWorkflows();\n\n // Scan rules\n let rulesCount = 0;\n try {\n const rules = await this.rulesSyncer.scanRules();\n rulesCount = rules.length;\n } catch {\n // Rules scan may fail if no rules exist\n }\n\n // Scan skills across all agents\n const { skills, conflicts: skillConflicts } = this.scanSkills();\n\n return { mcpConfigs, workflows, rulesCount, skills, skillConflicts };\n }\n\n /**\n * Migrate workspace configs to a target agent format.\n * @param items — optional list of specific item names (MCP servers / skills) to sync.\n * When provided, only matching items are included. Omit to sync all.\n */\n async migrate(target: AgentTarget, items?: string[]): Promise<WorkspaceSyncResult> {\n const scan = await this.scan();\n const result: WorkspaceSyncResult = {\n mcpServers: { scanned: [], generated: [] },\n workflows: { scanned: [], generated: [] },\n rules: { scanned: 0, generated: 0 },\n skills: { scanned: [], conflicts: [], copied: [], skipped: [] },\n };\n\n const itemFilter = items && items.length > 0\n ? new Set(items.map(i => i.toLowerCase()))\n : null;\n\n // 1. Merge all MCP servers from all sources (dedup by name)\n const allServers = new Map<string, MCPServerEntry>();\n for (const servers of Object.values(scan.mcpConfigs)) {\n for (const s of servers) {\n if (!allServers.has(s.name)) {\n if (!itemFilter || itemFilter.has(s.name.toLowerCase())) {\n allServers.set(s.name, s);\n }\n }\n }\n }\n result.mcpServers.scanned = Array.from(allServers.values());\n\n // Generate target MCP config (sanitize sensitive values in output)\n if (result.mcpServers.scanned.length > 0) {\n const adapter = this.adapters.get(target)!;\n const configPath = adapter.getConfigPath(this.projectRoot);\n let configContent: string;\n\n // For agents whose config file is shared (e.g. .gemini/settings.json\n // contains both hooks and mcpServers), merge instead of overwrite.\n if (target === 'antigravity' && existsSync(configPath)) {\n try {\n const existing = JSON.parse(readFileSync(configPath, 'utf-8'));\n const generated = JSON.parse(adapter.generate(result.mcpServers.scanned));\n existing.mcpServers = { ...(existing.mcpServers ?? {}), ...generated.mcpServers };\n configContent = JSON.stringify(existing, null, 2);\n } catch {\n configContent = adapter.generate(result.mcpServers.scanned);\n }\n } else {\n configContent = adapter.generate(result.mcpServers.scanned);\n }\n\n result.mcpServers.generated.push({\n filePath: configPath,\n content: sanitize(configContent),\n });\n }\n\n // 2. Convert workflows to target format\n result.workflows.scanned = scan.workflows;\n if (scan.workflows.length > 0) {\n result.workflows.generated = this.workflowSyncer.convertAll(scan.workflows, target);\n }\n\n // 3. Rules sync\n try {\n const rules = await this.rulesSyncer.scanRules();\n result.rules.scanned = rules.length;\n if (rules.length > 0) {\n const deduped = this.rulesSyncer.deduplicateRules(rules);\n const ruleSource = this.agentToRuleSource(target);\n if (ruleSource) {\n const files = this.rulesSyncer.generateForTarget(deduped, ruleSource);\n result.rules.generated = files.length;\n }\n }\n } catch {\n // Rules may not exist\n }\n\n // 4. Skills sync (no format conversion, just copy folders)\n result.skills.scanned = itemFilter\n ? scan.skills.filter(sk => itemFilter.has(sk.name.toLowerCase()))\n : scan.skills;\n result.skills.conflicts = scan.skillConflicts;\n\n return result;\n }\n\n // ---- Private helpers ----\n\n /** Skills directories per agent */\n private static SKILLS_DIRS: Record<AgentTarget, string[]> = {\n codex: ['.codex/skills', '.agents/skills'],\n cursor: ['.cursor/skills', '.cursor/skills-cursor'],\n windsurf: ['.windsurf/skills'],\n 'claude-code': ['.claude/skills'],\n copilot: ['.github/skills', '.copilot/skills'],\n antigravity: ['.agent/skills', '.gemini/skills', '.gemini/antigravity/skills'],\n kiro: ['.kiro/skills'],\n opencode: ['.opencode/skills'],\n trae: ['.trae/skills'],\n };\n\n /** Get the target skills directory for an agent (null if agent has no skills support) */\n private getTargetSkillsDir(target: AgentTarget): string | null {\n const dirs = WorkspaceSyncEngine.SKILLS_DIRS[target];\n if (!dirs || dirs.length === 0) return null;\n return join(this.projectRoot, dirs[0]);\n }\n\n /**\n * Scan all agent skills directories and collect unique skills.\n */\n private scanSkills(): { skills: SkillEntry[]; conflicts: SkillConflict[] } {\n const skills: SkillEntry[] = [];\n const conflicts: SkillConflict[] = [];\n const seen = new Map<string, SkillEntry>();\n const home = homedir();\n\n for (const [agent, dirs] of Object.entries(WorkspaceSyncEngine.SKILLS_DIRS)) {\n for (const dir of dirs) {\n // Check project-level and global\n const paths = [\n join(this.projectRoot, dir),\n join(home, dir),\n ];\n\n for (const skillsRoot of paths) {\n if (!existsSync(skillsRoot)) continue;\n\n try {\n const entries = readdirSync(skillsRoot, { withFileTypes: true });\n for (const entry of entries) {\n if (!entry.isDirectory()) continue;\n\n const skillMd = join(skillsRoot, entry.name, 'SKILL.md');\n if (!existsSync(skillMd)) continue;\n\n // Parse description from frontmatter\n let description = '';\n try {\n const content = readFileSync(skillMd, 'utf-8');\n const match = content.match(/^---[\\s\\S]*?description:\\s*[\"']?(.+?)[\"']?\\s*$/m);\n if (match) description = match[1];\n } catch { /* skip */ }\n\n const newEntry: SkillEntry = {\n name: entry.name,\n description,\n sourcePath: join(skillsRoot, entry.name),\n sourceAgent: agent as AgentTarget,\n };\n\n const existing = seen.get(entry.name);\n if (existing) {\n // Conflict: same name from different agent\n if (existing.sourceAgent !== agent) {\n conflicts.push({\n name: entry.name,\n kept: existing,\n skipped: newEntry,\n });\n }\n continue;\n }\n\n seen.set(entry.name, newEntry);\n skills.push(newEntry);\n }\n } catch { /* skip unreadable dirs */ }\n }\n }\n }\n\n return { skills, conflicts };\n }\n\n /**\n * Copy skills to a target agent's skills directory.\n * Returns list of copied skill names.\n */\n copySkills(skills: SkillEntry[], target: AgentTarget): { copied: string[]; skipped: string[] } {\n const targetDir = this.getTargetSkillsDir(target);\n const copied: string[] = [];\n const skipped: string[] = [];\n\n // Agent has no skills directory support (e.g. copilot)\n if (!targetDir) {\n return { copied, skipped };\n }\n\n for (const skill of skills) {\n // Don't copy a skill back to its own agent\n if (skill.sourceAgent === target) continue;\n\n const dest = join(targetDir, skill.name);\n if (existsSync(dest)) {\n skipped.push(`${skill.name} (already exists in ${target})`);\n continue;\n }\n\n try {\n mkdirSync(targetDir, { recursive: true });\n cpSync(skill.sourcePath, dest, { recursive: true });\n copied.push(skill.name);\n } catch { /* skip on error */ }\n }\n\n return { copied, skipped };\n }\n\n private scanWorkflows(): WorkflowEntry[] {\n const workflows: WorkflowEntry[] = [];\n const wfDir = join(this.projectRoot, '.windsurf', 'workflows');\n\n if (!existsSync(wfDir)) return workflows;\n\n try {\n const files = readdirSync(wfDir).filter((f) => f.endsWith('.md'));\n for (const file of files) {\n try {\n const content = readFileSync(join(wfDir, file), 'utf-8');\n workflows.push(this.workflowSyncer.parseWindsurfWorkflow(file, content));\n } catch {\n // Skip unreadable files\n }\n }\n } catch {\n // Directory read error\n }\n\n return workflows;\n }\n\n /**\n * Apply migration results to disk with backup and rollback.\n *\n * Safety features:\n * - Backs up every existing file before overwriting\n * - Atomic writes (temp → rename)\n * - Auto-rollback on any failure\n * - Returns backup paths for manual rollback if needed\n */\n async apply(target: AgentTarget, items?: string[]): Promise<ApplyResult & { migrationSummary: string }> {\n const syncResult = await this.migrate(target, items);\n const applier = new WorkspaceSyncApplier();\n\n // Collect all files to write\n const filesToWrite = [\n ...syncResult.mcpServers.generated,\n ...syncResult.workflows.generated,\n ];\n\n const applyResult = await applier.apply(filesToWrite);\n\n // Copy skills (no format conversion needed)\n let skillResult = { copied: [] as string[], skipped: [] as string[] };\n if (syncResult.skills.scanned.length > 0) {\n skillResult = this.copySkills(syncResult.skills.scanned, target);\n }\n\n // Build summary\n const lines: string[] = [];\n if (applyResult.success) {\n lines.push(`✅ Applied ${applyResult.filesWritten.length} file(s) for ${target}`);\n for (const f of applyResult.filesWritten) {\n lines.push(` → ${f}`);\n }\n if (skillResult.copied.length > 0) {\n lines.push(`\\n🧩 Copied ${skillResult.copied.length} skill(s):`);\n for (const sk of skillResult.copied) {\n lines.push(` → ${sk}`);\n }\n }\n if (skillResult.skipped.length > 0) {\n lines.push(`\\n⏭️ Skipped ${skillResult.skipped.length} skill(s):`);\n for (const sk of skillResult.skipped) {\n lines.push(` → ${sk}`);\n }\n }\n if (syncResult.skills.conflicts.length > 0) {\n lines.push(`\\n⚠️ Name conflicts (${syncResult.skills.conflicts.length}):`);\n for (const c of syncResult.skills.conflicts) {\n lines.push(` → \"${c.name}\": kept ${c.kept.sourceAgent}, skipped ${c.skipped.sourceAgent}`);\n }\n }\n if (applyResult.backups.length > 0) {\n lines.push(`\\n📦 Backups created (${applyResult.backups.length}):`);\n for (const b of applyResult.backups) {\n lines.push(` ${b.originalPath} → ${b.backupPath}`);\n }\n }\n // Clean up backups after successful apply\n applier.cleanBackups(applyResult.backups);\n } else {\n lines.push(`❌ Apply failed for ${target}`);\n for (const e of applyResult.errors) {\n lines.push(` Error: ${e}`);\n }\n if (applyResult.backups.length > 0) {\n lines.push(`\\n🔄 Rolled back ${applyResult.backups.length} file(s)`);\n }\n }\n\n return {\n ...applyResult,\n migrationSummary: lines.join('\\n'),\n };\n }\n\n // ---- Private helpers ----\n\n private agentToRuleSource(target: AgentTarget): RuleSource | null {\n const map: Record<AgentTarget, RuleSource> = {\n cursor: 'cursor',\n 'claude-code': 'claude-code',\n codex: 'codex',\n windsurf: 'windsurf',\n copilot: 'copilot',\n antigravity: 'antigravity',\n kiro: 'kiro',\n opencode: 'codex',\n trae: 'trae',\n };\n return map[target] ?? null;\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Windsurf MCP config adapter.\n * Format: JSON file at ~/.codeium/windsurf/mcp_config.json\n *\n * Supports two transport modes:\n * 1. stdio: { command, args, env? }\n * 2. HTTP: { serverUrl, headers? }\n *\n * Also handles: disabled, disabledTools, env: null\n */\nexport class WindsurfMCPAdapter implements MCPConfigAdapter {\n readonly source = 'windsurf' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcpServers ?? config.mcp_servers ?? {};\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\n const result: MCPServerEntry = {\n name,\n command: entry.command ?? '',\n args: entry.args ?? [],\n };\n\n // HTTP transport: Windsurf uses \"serverUrl\" (not \"url\")\n if (entry.serverUrl) {\n result.url = entry.serverUrl;\n } else if (entry.url) {\n result.url = entry.url;\n }\n\n // Headers (for HTTP transport)\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\n result.headers = entry.headers;\n }\n\n // Env (can be null in Windsurf)\n if (entry.env && typeof entry.env === 'object' && Object.keys(entry.env).length > 0) {\n result.env = entry.env;\n }\n\n // Disabled flag\n if (entry.disabled === true) {\n result.disabled = true;\n }\n\n return result;\n });\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n\n if (s.url) {\n // HTTP transport — Windsurf uses \"serverUrl\"\n entry.serverUrl = s.url;\n if (s.headers && Object.keys(s.headers).length > 0) {\n entry.headers = s.headers;\n }\n } else {\n // stdio transport\n entry.command = s.command;\n entry.args = s.args;\n }\n\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n\n if (s.disabled === true) {\n entry.disabled = true;\n }\n\n mcpServers[s.name] = entry;\n }\n return JSON.stringify({ mcpServers }, null, 2);\n }\n\n getConfigPath(_projectRoot?: string): string {\n return join(homedir(), '.codeium', 'windsurf', 'mcp_config.json');\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Cursor MCP config adapter.\n * Format: JSON file at ~/.cursor/mcp.json or .cursor/mcp.json (project-level)\n * Structure: { mcpServers: { [name]: { command, args, env?, url? } } }\n */\nexport class CursorMCPAdapter implements MCPConfigAdapter {\n readonly source = 'cursor' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcpServers ?? {};\n return Object.entries(servers).map(([name, entry]: [string, any]) => ({\n name,\n command: entry.command ?? '',\n args: entry.args ?? [],\n ...(entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\n ...(entry.url ? { url: entry.url } : {}),\n }));\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n if (s.url) {\n entry.url = s.url;\n } else {\n entry.command = s.command;\n entry.args = s.args;\n }\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n mcpServers[s.name] = entry;\n }\n return JSON.stringify({ mcpServers }, null, 2);\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n return join(projectRoot, '.cursor', 'mcp.json');\n }\n return join(homedir(), '.cursor', 'mcp.json');\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Codex MCP config adapter.\n * Format: TOML file at ~/.codex/config.toml or .codex/config.toml (project-level)\n *\n * Structure:\n * [mcp_servers.<name>]\n * command = \"npx\"\n * args = [\"-y\", \"memorix-mcp\"]\n * url = \"https://...\" # for HTTP servers\n *\n * [mcp_servers.<name>.env]\n * KEY = \"value\"\n *\n * We implement a lightweight TOML parser (no external deps) sufficient\n * for MCP server config blocks. This avoids adding a TOML dependency.\n */\nexport class CodexMCPAdapter implements MCPConfigAdapter {\n readonly source = 'codex' as const;\n\n parse(content: string): MCPServerEntry[] {\n if (!content.trim()) return [];\n\n const servers: MCPServerEntry[] = [];\n const lines = content.split('\\n');\n\n let currentServer: string | null = null;\n let isEnvBlock = false;\n const serverMap = new Map<\n string,\n { command: string; args: string[]; env: Record<string, string>; url?: string; enabled?: boolean }\n >();\n\n for (const rawLine of lines) {\n const line = rawLine.trim();\n\n // Skip comments and empty lines\n if (!line || line.startsWith('#')) continue;\n\n // Match [mcp_servers.<name>.env]\n const envMatch = line.match(/^\\[mcp_servers\\.([^.\\]]+)\\.env\\]$/);\n if (envMatch) {\n currentServer = envMatch[1];\n isEnvBlock = true;\n if (!serverMap.has(currentServer)) {\n serverMap.set(currentServer, { command: '', args: [], env: {} });\n }\n continue;\n }\n\n // Match [mcp_servers.<name>]\n const serverMatch = line.match(/^\\[mcp_servers\\.([^.\\]]+)\\]$/);\n if (serverMatch) {\n currentServer = serverMatch[1];\n isEnvBlock = false;\n if (!serverMap.has(currentServer)) {\n serverMap.set(currentServer, { command: '', args: [], env: {} });\n }\n continue;\n }\n\n // Any other section header resets context\n if (line.startsWith('[')) {\n currentServer = null;\n isEnvBlock = false;\n continue;\n }\n\n // Parse key = value within current server block\n if (currentServer) {\n const kvMatch = line.match(/^(\\w+)\\s*=\\s*(.+)$/);\n if (!kvMatch) continue;\n\n const key = kvMatch[1];\n const rawValue = kvMatch[2].trim();\n const entry = serverMap.get(currentServer)!;\n\n if (isEnvBlock) {\n entry.env[key] = this.parseTomlString(rawValue);\n } else if (key === 'command') {\n entry.command = this.parseTomlString(rawValue);\n } else if (key === 'args') {\n entry.args = this.parseTomlArray(rawValue);\n } else if (key === 'url') {\n entry.url = this.parseTomlString(rawValue);\n } else if (key === 'enabled') {\n entry.enabled = rawValue === 'true';\n }\n }\n }\n\n for (const [name, entry] of serverMap) {\n servers.push({\n name,\n command: entry.command,\n args: entry.args,\n ...(Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\n ...(entry.url ? { url: entry.url } : {}),\n });\n }\n\n return servers;\n }\n\n generate(servers: MCPServerEntry[]): string {\n const blocks: string[] = [];\n\n for (const s of servers) {\n const lines: string[] = [];\n lines.push(`[mcp_servers.${s.name}]`);\n\n if (s.url) {\n lines.push(`url = ${this.toTomlString(s.url)}`);\n } else {\n lines.push(`command = ${this.toTomlString(s.command)}`);\n lines.push(`args = [${s.args.map((a) => this.toTomlString(a)).join(', ')}]`);\n }\n\n if (s.env && Object.keys(s.env).length > 0) {\n lines.push('');\n lines.push(`[mcp_servers.${s.name}.env]`);\n for (const [key, value] of Object.entries(s.env)) {\n lines.push(`${key} = ${this.toTomlString(value)}`);\n }\n }\n\n blocks.push(lines.join('\\n'));\n }\n\n return blocks.join('\\n\\n') + '\\n';\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n return join(projectRoot, '.codex', 'config.toml');\n }\n return join(homedir(), '.codex', 'config.toml');\n }\n\n // ---- TOML helpers ----\n\n private parseTomlString(raw: string): string {\n const trimmed = raw.trim();\n if (\n (trimmed.startsWith('\"') && trimmed.endsWith('\"')) ||\n (trimmed.startsWith(\"'\") && trimmed.endsWith(\"'\"))\n ) {\n return trimmed.slice(1, -1);\n }\n return trimmed;\n }\n\n private parseTomlArray(raw: string): string[] {\n const trimmed = raw.trim();\n if (!trimmed.startsWith('[') || !trimmed.endsWith(']')) return [];\n const inner = trimmed.slice(1, -1);\n const result: string[] = [];\n // Simple CSV parse respecting quotes\n let current = '';\n let inQuote = false;\n let quoteChar = '';\n for (const ch of inner) {\n if (inQuote) {\n if (ch === quoteChar) {\n inQuote = false;\n } else {\n current += ch;\n }\n } else if (ch === '\"' || ch === \"'\") {\n inQuote = true;\n quoteChar = ch;\n } else if (ch === ',') {\n const val = current.trim();\n if (val) result.push(val);\n current = '';\n } else {\n current += ch;\n }\n }\n const last = current.trim();\n if (last) result.push(last);\n return result;\n }\n\n private toTomlString(value: string): string {\n return `\"${value.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * Claude Code MCP config adapter.\n * Format: JSON file at ~/.claude.json or project-level .claude/settings.json\n * Structure: { mcpServers: { [name]: { command, args, env?, url? } } }\n */\nexport class ClaudeCodeMCPAdapter implements MCPConfigAdapter {\n readonly source = 'claude-code' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcpServers ?? {};\n return Object.entries(servers).map(([name, entry]: [string, any]) => ({\n name,\n command: entry.command ?? '',\n args: entry.args ?? [],\n ...(entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\n ...(entry.url ? { url: entry.url } : {}),\n }));\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n if (s.url) {\n entry.url = s.url;\n } else {\n entry.command = s.command;\n entry.args = s.args;\n }\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n mcpServers[s.name] = entry;\n }\n return JSON.stringify({ mcpServers }, null, 2);\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n return join(projectRoot, '.claude', 'settings.json');\n }\n return join(homedir(), '.claude.json');\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * VS Code Copilot MCP config adapter.\n *\n * Supports two config locations / formats:\n *\n * 1. Workspace-level (preferred, new):\n * Path: .vscode/mcp.json\n * Format: { \"servers\": { [name]: { command, args, env?, url? } } }\n *\n * 2. Global (legacy, still scanned):\n * Path: %APPDATA%/Code/User/settings.json\n * Format: { \"mcp\": { \"servers\": { [name]: { command, args, env? } } } }\n *\n * parse() auto-detects which format is provided.\n * generate() always outputs the new .vscode/mcp.json format.\n * getConfigPath(projectRoot) returns workspace path; getConfigPath() returns global path.\n */\nexport class CopilotMCPAdapter implements MCPConfigAdapter {\n readonly source = 'copilot' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n\n // Auto-detect format:\n // 1. mcp.json format: { \"servers\": { ... } }\n // 2. settings.json format: { \"mcp\": { \"servers\": { ... } } }\n const servers = config?.servers ?? config?.mcp?.servers ?? {};\n\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\n const result: MCPServerEntry = {\n name,\n command: entry.command ?? '',\n args: entry.args ?? [],\n };\n\n if (entry.type) {\n // VS Code mcp.json supports \"type\" field (e.g., \"http\", \"stdio\")\n // Map to url for HTTP types\n if ((entry.type === 'http' || entry.type === 'sse') && entry.url) {\n result.url = entry.url;\n }\n } else if (entry.url) {\n result.url = entry.url;\n }\n\n if (entry.env && typeof entry.env === 'object' && Object.keys(entry.env).length > 0) {\n result.env = entry.env;\n }\n\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\n result.headers = entry.headers;\n }\n\n return result;\n });\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n if (s.url) {\n entry.type = 'http';\n entry.url = s.url;\n if (s.headers && Object.keys(s.headers).length > 0) {\n entry.headers = s.headers;\n }\n } else {\n entry.command = s.command;\n entry.args = s.args;\n }\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n mcpServers[s.name] = entry;\n }\n\n // Output the new .vscode/mcp.json format: { \"servers\": { ... } }\n return JSON.stringify({ servers: mcpServers }, null, 2);\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n // Workspace-level: .vscode/mcp.json (new official format)\n return join(projectRoot, '.vscode', 'mcp.json');\n }\n // Global: VS Code user settings path (legacy, for scan fallback)\n const home = homedir();\n if (process.platform === 'win32') {\n return join(home, 'AppData', 'Roaming', 'Code', 'User', 'settings.json');\n } else if (process.platform === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Code', 'User', 'settings.json');\n } else {\n return join(home, '.config', 'Code', 'User', 'settings.json');\n }\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\r\nimport { homedir } from 'node:os';\r\nimport { join } from 'node:path';\r\n\r\n/**\r\n * Antigravity IDE MCP Configuration Adapter.\r\n *\r\n * Antigravity uses two JSON config files for MCP servers:\r\n * 1. Global MCP: ~/.gemini/antigravity/mcp_config.json\r\n * Format: { \"mcpServers\": { \"name\": { command, args, env? } } }\r\n *\r\n * 2. Global settings: ~/.gemini/settings.json\r\n * Format: { \"mcpServers\": { \"name\": { command, args, env? } } }\r\n *\r\n * The mcp_config.json format is the primary config, same JSON structure\r\n * as Windsurf but at a different path. Also supports HTTP transport via url.\r\n *\r\n * Source: Antigravity official documentation (https://antigravity.google/docs/agent/mcp)\r\n * Verified on local machine: C:\\Users\\<USER>\\.gemini\\antigravity\\mcp_config.json\r\n */\r\nexport class AntigravityMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'antigravity' as const;\r\n\r\n parse(content: string): MCPServerEntry[] {\r\n try {\r\n const config = JSON.parse(content);\r\n const servers = config.mcpServers ?? config.mcp_servers ?? {};\r\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\r\n const result: MCPServerEntry = {\r\n name,\r\n command: entry.command ?? '',\r\n args: entry.args ?? [],\r\n };\r\n\r\n // HTTP transport\r\n if (entry.serverUrl) {\r\n result.url = entry.serverUrl;\r\n } else if (entry.url) {\r\n result.url = entry.url;\r\n }\r\n\r\n // Headers (for HTTP transport)\r\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\r\n result.headers = entry.headers;\r\n }\r\n\r\n // Env\r\n if (entry.env && typeof entry.env === 'object' && Object.keys(entry.env).length > 0) {\r\n result.env = entry.env;\r\n }\r\n\r\n // Disabled flag\r\n if (entry.disabled === true) {\r\n result.disabled = true;\r\n }\r\n\r\n return result;\r\n });\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n generate(servers: MCPServerEntry[]): string {\r\n const mcpServers: Record<string, any> = {};\r\n for (const s of servers) {\r\n const entry: Record<string, any> = {};\r\n\r\n if (s.url) {\r\n // HTTP transport\r\n entry.url = s.url;\r\n if (s.headers && Object.keys(s.headers).length > 0) {\r\n entry.headers = s.headers;\r\n }\r\n } else {\r\n // stdio transport\r\n entry.command = s.command;\r\n entry.args = s.args;\r\n }\r\n\r\n if (s.env && Object.keys(s.env).length > 0) {\r\n entry.env = s.env;\r\n }\r\n\r\n if (s.disabled === true) {\r\n entry.disabled = true;\r\n }\r\n\r\n mcpServers[s.name] = entry;\r\n }\r\n return JSON.stringify({ mcpServers }, null, 2);\r\n }\r\n\r\n getConfigPath(projectRoot?: string): string {\r\n if (projectRoot) {\r\n // Project-level: .gemini/settings.json (shared with hooks)\r\n return join(projectRoot, '.gemini', 'settings.json');\r\n }\r\n // Global: ~/.gemini/settings.json\r\n return join(homedir(), '.gemini', 'settings.json');\r\n }\r\n}\r\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\r\nimport { homedir } from 'node:os';\r\nimport { join } from 'node:path';\r\n\r\n/**\r\n * Kiro MCP config adapter.\r\n * Format: JSON file at .kiro/settings/mcp.json (project-level)\r\n * or ~/.kiro/settings/mcp.json (user-level)\r\n * Structure: { mcpServers: { ... }, powers?: { mcpServers: { ... } } }\r\n *\r\n * Kiro stores user-added servers in `mcpServers` and power-installed\r\n * servers (context7, figma, postman, supabase etc.) in `powers.mcpServers`.\r\n * Both sections use the same entry format.\r\n *\r\n * Source: Kiro official MCP documentation.\r\n */\r\nexport class KiroMCPAdapter implements MCPConfigAdapter {\r\n readonly source = 'kiro' as const;\r\n\r\n parse(content: string): MCPServerEntry[] {\r\n try {\r\n const config = JSON.parse(content);\r\n // Merge top-level mcpServers and powers.mcpServers (dedup by name)\r\n const topLevel = config.mcpServers ?? {};\r\n const powers = config.powers?.mcpServers ?? {};\r\n const merged = { ...powers, ...topLevel };\r\n return Object.entries(merged).map(([name, entry]: [string, any]) => ({\r\n name,\r\n command: entry.command ?? '',\r\n args: entry.args ?? [],\r\n ...(entry.env && Object.keys(entry.env).length > 0 ? { env: entry.env } : {}),\r\n ...(entry.url ? { url: entry.url } : {}),\r\n ...(entry.disabled === true ? { disabled: true } : {}),\r\n }));\r\n } catch {\r\n return [];\r\n }\r\n }\r\n\r\n generate(servers: MCPServerEntry[]): string {\r\n const mcpServers: Record<string, any> = {};\r\n for (const s of servers) {\r\n const entry: Record<string, any> = {};\r\n if (s.url) {\r\n entry.url = s.url;\r\n } else {\r\n entry.command = s.command;\r\n entry.args = s.args;\r\n }\r\n if (s.env && Object.keys(s.env).length > 0) {\r\n entry.env = s.env;\r\n }\r\n mcpServers[s.name] = entry;\r\n }\r\n return JSON.stringify({ mcpServers }, null, 2);\r\n }\r\n\r\n getConfigPath(projectRoot?: string): string {\r\n if (projectRoot) {\r\n return join(projectRoot, '.kiro', 'settings', 'mcp.json');\r\n }\r\n return join(homedir(), '.kiro', 'settings', 'mcp.json');\r\n }\r\n}\r\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { homedir } from 'node:os';\nimport { join } from 'node:path';\n\n/**\n * OpenCode MCP Configuration Adapter.\n *\n * OpenCode uses JSON config files for MCP servers:\n * 1. Project-level: opencode.json in project root\n * 2. Global: ~/.config/opencode/opencode.json\n *\n * Format:\n * {\n * \"$schema\": \"https://opencode.ai/config.json\",\n * \"mcp\": {\n * \"name\": {\n * \"type\": \"local\",\n * \"command\": [\"memorix\", \"serve\"],\n * \"environment\": { \"KEY\": \"value\" },\n * \"enabled\": true\n * }\n * }\n * }\n *\n * Remote (HTTP) servers:\n * {\n * \"mcp\": {\n * \"name\": {\n * \"type\": \"remote\",\n * \"url\": \"https://...\",\n * \"headers\": { \"Authorization\": \"Bearer ...\" }\n * }\n * }\n * }\n *\n * Source: https://opencode.ai/docs/mcp-servers/\n */\nexport class OpenCodeMCPAdapter implements MCPConfigAdapter {\n readonly source = 'opencode' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcp ?? {};\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\n const result: MCPServerEntry = {\n name,\n command: '',\n args: [],\n };\n\n if (entry.type === 'remote' && entry.url) {\n // HTTP transport\n result.url = entry.url;\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\n result.headers = entry.headers;\n }\n } else {\n // Local (stdio) transport — command is an array in OpenCode\n if (Array.isArray(entry.command) && entry.command.length > 0) {\n result.command = entry.command[0];\n result.args = entry.command.slice(1);\n } else if (typeof entry.command === 'string') {\n result.command = entry.command;\n }\n }\n\n // Environment variables (OpenCode uses \"environment\" not \"env\")\n const env = entry.environment ?? entry.env;\n if (env && typeof env === 'object' && Object.keys(env).length > 0) {\n result.env = env;\n }\n\n // Disabled flag\n if (entry.enabled === false) {\n result.disabled = true;\n }\n\n return result;\n });\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcp: Record<string, any> = {};\n for (const s of servers) {\n const entry: Record<string, any> = {};\n\n if (s.url) {\n // HTTP transport\n entry.type = 'remote';\n entry.url = s.url;\n if (s.headers && Object.keys(s.headers).length > 0) {\n entry.headers = s.headers;\n }\n } else {\n // stdio transport — OpenCode uses command as array\n entry.type = 'local';\n entry.command = [s.command, ...s.args];\n }\n\n if (s.env && Object.keys(s.env).length > 0) {\n entry.environment = s.env;\n }\n\n if (s.disabled === true) {\n entry.enabled = false;\n }\n\n mcp[s.name] = entry;\n }\n return JSON.stringify({ $schema: 'https://opencode.ai/config.json', mcp }, null, 2);\n }\n\n getConfigPath(projectRoot?: string): string {\n if (projectRoot) {\n return join(projectRoot, 'opencode.json');\n }\n return join(homedir(), '.config', 'opencode', 'opencode.json');\n }\n}\n","import type { MCPConfigAdapter, MCPServerEntry } from '../../types.js';\nimport { join } from 'node:path';\nimport { homedir } from 'node:os';\n\n/**\n * Trae IDE MCP Configuration Adapter.\n *\n * Trae stores MCP config at the user level:\n * %APPDATA%/Trae/User/mcp.json (Windows)\n * ~/Library/Application Support/Trae/User/mcp.json (macOS)\n * ~/.config/Trae/User/mcp.json (Linux)\n *\n * Format (OBJECT-keyed, same as Cursor):\n * {\n * \"mcpServers\": {\n * \"memorix\": {\n * \"command\": \"memorix\",\n * \"args\": [\"serve\"],\n * \"env\": { \"KEY\": \"value\" }\n * }\n * }\n * }\n *\n * SSE transport:\n * {\n * \"mcpServers\": {\n * \"remote\": {\n * \"url\": \"https://...\",\n * \"type\": \"sse\"\n * }\n * }\n * }\n *\n * Source: https://docs.trae.ai/ide/model-context-protocol\n */\nexport class TraeMCPAdapter implements MCPConfigAdapter {\n readonly source = 'trae' as const;\n\n parse(content: string): MCPServerEntry[] {\n try {\n const config = JSON.parse(content);\n const servers = config.mcpServers;\n\n if (!servers || typeof servers !== 'object') return [];\n\n // Object-keyed format: { \"mcpServers\": { \"name\": { ... } } }\n return Object.entries(servers).map(([name, entry]: [string, any]) => {\n const result: MCPServerEntry = {\n name,\n command: '',\n args: [],\n };\n\n if (typeof entry.command === 'string') {\n result.command = entry.command;\n }\n\n if (Array.isArray(entry.args)) {\n result.args = entry.args;\n }\n\n // SSE/HTTP transport\n if (entry.url) {\n result.url = entry.url;\n }\n\n // Environment variables\n if (entry.env && typeof entry.env === 'object' && Object.keys(entry.env).length > 0) {\n result.env = entry.env;\n }\n\n // Headers (for HTTP transport)\n if (entry.headers && typeof entry.headers === 'object' && Object.keys(entry.headers).length > 0) {\n result.headers = entry.headers;\n }\n\n // Disabled flag\n if (entry.disabled === true) {\n result.disabled = true;\n }\n\n return result;\n });\n } catch {\n return [];\n }\n }\n\n generate(servers: MCPServerEntry[]): string {\n const mcpServers: Record<string, any> = {};\n\n for (const s of servers) {\n const entry: Record<string, any> = {};\n\n if (s.url) {\n // SSE/HTTP transport\n entry.url = s.url;\n if (s.headers && Object.keys(s.headers).length > 0) {\n entry.headers = s.headers;\n }\n } else {\n // stdio transport\n entry.command = s.command;\n if (s.args && s.args.length > 0) {\n entry.args = s.args;\n }\n }\n\n if (s.env && Object.keys(s.env).length > 0) {\n entry.env = s.env;\n }\n\n if (s.disabled === true) {\n entry.disabled = true;\n }\n\n mcpServers[s.name] = entry;\n }\n\n return JSON.stringify({ mcpServers }, null, 2);\n }\n\n getConfigPath(_projectRoot?: string): string {\n const home = homedir();\n // Trae stores user-level MCP config in AppData (Windows) / Application Support (macOS) / .config (Linux)\n if (process.platform === 'win32') {\n return join(process.env.APPDATA || join(home, 'AppData', 'Roaming'), 'Trae', 'User', 'mcp.json');\n }\n if (process.platform === 'darwin') {\n return join(home, 'Library', 'Application Support', 'Trae', 'User', 'mcp.json');\n }\n return join(home, '.config', 'Trae', 'User', 'mcp.json');\n }\n}\n","import matter from 'gray-matter';\nimport type { AgentTarget, WorkflowEntry } from '../types.js';\n\n/**\n * WorkflowSyncer — converts workflows between agent formats.\n *\n * Supported conversions:\n * Windsurf .windsurf/workflows/*.md → Codex SKILL.md\n * Windsurf .windsurf/workflows/*.md → Cursor .cursor/rules/*.mdc\n * Windsurf .windsurf/workflows/*.md → Claude Code CLAUDE.md section\n */\nexport class WorkflowSyncer {\n /**\n * Parse a Windsurf workflow markdown file into a WorkflowEntry.\n */\n parseWindsurfWorkflow(fileName: string, raw: string): WorkflowEntry {\n const name = fileName.replace(/\\.md$/i, '');\n let description = '';\n let content = raw;\n\n try {\n const parsed = matter(raw);\n description = parsed.data?.description ?? '';\n content = parsed.content.trim();\n } catch {\n // No frontmatter — use raw content\n }\n\n return {\n name,\n description,\n content,\n source: 'windsurf',\n filePath: `.windsurf/workflows/${fileName}`,\n };\n }\n\n /**\n * Convert a workflow to Codex SKILL.md format.\n */\n toCodexSkill(wf: WorkflowEntry): { filePath: string; content: string } {\n const safeName = this.sanitizeName(wf.name);\n const fm: Record<string, string> = { name: safeName };\n if (wf.description) {\n fm.description = wf.description;\n }\n const content = matter.stringify(wf.content, fm);\n return {\n filePath: `.agents/skills/${safeName}/SKILL.md`,\n content,\n };\n }\n\n /**\n * Convert a workflow to Cursor .mdc rule format.\n */\n toCursorRule(wf: WorkflowEntry): { filePath: string; content: string } {\n const safeName = this.sanitizeName(wf.name);\n const fm: Record<string, string> = {};\n if (wf.description) {\n fm.description = wf.description;\n }\n fm.globs = '';\n fm.alwaysApply = 'false';\n const content = matter.stringify(wf.content, fm);\n return {\n filePath: `.cursor/rules/${safeName}.mdc`,\n content,\n };\n }\n\n /**\n * Convert a workflow to a CLAUDE.md section string.\n */\n toClaudeSection(wf: WorkflowEntry): string {\n const lines: string[] = [];\n lines.push(`## Workflow: ${wf.name}`);\n if (wf.description) {\n lines.push('');\n lines.push(`> ${wf.description}`);\n }\n lines.push('');\n lines.push(wf.content);\n return lines.join('\\n');\n }\n\n /**\n * Convert all workflows to the target agent format.\n * Returns an array of { filePath, content } for each generated file.\n */\n convertAll(\n workflows: WorkflowEntry[],\n target: AgentTarget,\n ): { filePath: string; content: string }[] {\n if (target === 'windsurf') {\n // No conversion needed — already in Windsurf format\n return [];\n }\n\n if (target === 'codex') {\n return workflows.map((wf) => this.toCodexSkill(wf));\n }\n\n if (target === 'cursor') {\n return workflows.map((wf) => this.toCursorRule(wf));\n }\n\n if (target === 'claude-code') {\n // Merge all workflows into a single CLAUDE.md\n const sections = workflows.map((wf) => this.toClaudeSection(wf));\n return [\n {\n filePath: 'CLAUDE.md',\n content: sections.join('\\n\\n'),\n },\n ];\n }\n\n return [];\n }\n\n // ---- Helpers ----\n\n private sanitizeName(name: string): string {\n return name\n .replace(/[^a-zA-Z0-9_-]/g, '-')\n .replace(/-+/g, '-')\n .replace(/^-|-$/g, '')\n || 'workflow';\n }\n}\n","/**\n * Sanitizer — mask sensitive values (tokens, keys, passwords) in output.\n *\n * Patterns detected:\n * - API keys / tokens (github_pat_*, ctx7sk-*, sk-*, ghp_*, ghu_*, etc.)\n * - Generic key=value where key contains \"token\", \"key\", \"secret\", \"password\"\n * - Bearer tokens\n */\n\nconst SENSITIVE_PATTERNS: { pattern: RegExp; replacement: string }[] = [\n // GitHub PAT (classic & fine-grained)\n { pattern: /ghp_[A-Za-z0-9_]{36,}/g, replacement: 'ghp_***' },\n { pattern: /github_pat_[A-Za-z0-9_]{60,}/g, replacement: 'github_pat_***' },\n { pattern: /ghu_[A-Za-z0-9_]{36,}/g, replacement: 'ghu_***' },\n { pattern: /ghs_[A-Za-z0-9_]{36,}/g, replacement: 'ghs_***' },\n // OpenAI / Anthropic style keys\n { pattern: /sk-[A-Za-z0-9_-]{20,}/g, replacement: 'sk-***' },\n // Context7 keys\n { pattern: /ctx7sk-[A-Za-z0-9-]{20,}/g, replacement: 'ctx7sk-***' },\n // Generic long hex/base64 tokens (32+ chars) in quoted values\n { pattern: /\"([A-Za-z0-9_-]{40,})\"/g, replacement: '\"***\"' },\n];\n\nconst SENSITIVE_KEY_PATTERN = /(?:token|key|secret|password|credential|auth)/i;\n\n/**\n * Mask sensitive values in a string.\n */\nexport function sanitize(input: string): string {\n let result = input;\n\n // Apply known token patterns\n for (const { pattern, replacement } of SENSITIVE_PATTERNS) {\n // Reset lastIndex for global regexes\n pattern.lastIndex = 0;\n result = result.replace(pattern, replacement);\n }\n\n return result;\n}\n\n/**\n * Mask sensitive values in MCPServerEntry env/headers objects.\n * Returns a new object with masked values.\n */\nexport function sanitizeRecord(\n record: Record<string, string> | undefined | null,\n): Record<string, string> | undefined {\n if (!record) return undefined;\n\n const masked: Record<string, string> = {};\n for (const [key, value] of Object.entries(record)) {\n if (SENSITIVE_KEY_PATTERN.test(key)) {\n masked[key] = '***';\n } else {\n masked[key] = value;\n }\n }\n return masked;\n}\n","/**\n * Workspace Sync Applier\n *\n * Writes generated workspace sync results to disk with safety features:\n * 1. Pre-flight validation (check writability)\n * 2. Backup existing files before overwrite\n * 3. Atomic write (write to temp, then rename)\n * 4. Rollback on failure\n *\n * Usage:\n * const applier = new WorkspaceSyncApplier();\n * const result = await applier.apply(syncResult);\n * if (!result.success) await applier.rollback(result.backups);\n */\n\nimport { existsSync, mkdirSync, copyFileSync, writeFileSync, unlinkSync, renameSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\nexport interface ApplyResult {\n success: boolean;\n filesWritten: string[];\n backups: BackupEntry[];\n errors: string[];\n}\n\nexport interface BackupEntry {\n originalPath: string;\n backupPath: string;\n}\n\ninterface FileToWrite {\n filePath: string;\n content: string;\n}\n\n/**\n * Apply workspace sync results to disk with backup and rollback.\n */\nexport class WorkspaceSyncApplier {\n /**\n * Apply generated files to disk.\n *\n * Steps:\n * 1. Validate all target directories exist or can be created\n * 2. Backup existing files\n * 3. Write new files\n * 4. On any error → rollback all changes\n */\n async apply(files: FileToWrite[]): Promise<ApplyResult> {\n const result: ApplyResult = {\n success: false,\n filesWritten: [],\n backups: [],\n errors: [],\n };\n\n if (files.length === 0) {\n result.success = true;\n return result;\n }\n\n // Step 1: Pre-flight — ensure all directories exist\n for (const file of files) {\n try {\n const dir = dirname(file.filePath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n } catch (err) {\n result.errors.push(`Cannot create directory for ${file.filePath}: ${err}`);\n return result;\n }\n }\n\n // Step 2: Backup existing files\n for (const file of files) {\n if (existsSync(file.filePath)) {\n try {\n const backupPath = file.filePath + `.backup-${Date.now()}`;\n copyFileSync(file.filePath, backupPath);\n result.backups.push({\n originalPath: file.filePath,\n backupPath,\n });\n } catch (err) {\n result.errors.push(`Cannot backup ${file.filePath}: ${err}`);\n return result;\n }\n }\n }\n\n // Step 3: Write new files\n for (const file of files) {\n try {\n // Write to temp file first, then rename (pseudo-atomic)\n const tempPath = file.filePath + `.tmp-${Date.now()}`;\n writeFileSync(tempPath, file.content, 'utf-8');\n renameSync(tempPath, file.filePath);\n result.filesWritten.push(file.filePath);\n } catch (err) {\n result.errors.push(`Cannot write ${file.filePath}: ${err}`);\n // Rollback everything written so far\n this.rollback(result.backups);\n return result;\n }\n }\n\n result.success = true;\n return result;\n }\n\n /**\n * Rollback applied changes by restoring backups.\n */\n rollback(backups: BackupEntry[]): { restored: number; errors: string[] } {\n const errors: string[] = [];\n let restored = 0;\n\n for (const backup of backups) {\n try {\n copyFileSync(backup.backupPath, backup.originalPath);\n restored++;\n } catch (err) {\n errors.push(`Cannot restore ${backup.originalPath} from ${backup.backupPath}: ${err}`);\n }\n }\n\n return { restored, errors };\n }\n\n /**\n * Clean up backup files after successful apply.\n */\n cleanBackups(backups: BackupEntry[]): void {\n for (const backup of backups) {\n try {\n if (existsSync(backup.backupPath)) {\n unlinkSync(backup.backupPath);\n }\n } catch {\n // Best-effort cleanup\n }\n }\n }\n}\n"],"mappings":"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","names":["path","projectDir","fs","path","projectDir","observations","nextId","join","homedir","cache","MAX_CACHE_SIZE","createHash","readFile","writeFile","mkdir","join","homedir","textHash","loadDiskCache","CACHE_FILE","cache","diskCacheDirty","CACHE_DIR","MAX_CACHE_SIZE","MAX_RETRIES","getEmbeddingMode","FastEmbedProvider","TransformersProvider","APIEmbeddingProvider","fs","path","os","DEFAULT_DATA_DIR","getLLMApiKey","getLLMProvider","getLLMModel","getLLMBaseUrl","provider","init_provider","init_provider","provider","resolveAliases","rerankResults","getAllObservations","getObservationCount","removeObservation","count","init_provider","projectDir","projectDir","access","existsSync","readFileSync","writeFileSync","mkdirSync","readdirSync","join","homedir","observations","projectDir","observations","nextId","projectDir","MAX_BATCH_SIZE","projectDir","count","OBSERVATION_ICONS","observations","nextId","fs","path","getCanonicalId","count","observations","nextId","getEmbeddingProvider","isImmune","agent","count","randomUUID","count","count","randomUUID","count","persistence_exports","readFile","writeFile","mkdir","renameSync","existsSync","dirname","init_persistence","unlinkSync","fs","path","os","projectDir","observations","basename","existsSync","readFileSync","os","path","id","name","basename","fs","path","createHash","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","matter","fs","path","readFileSync","existsSync","mkdirSync","join","homedir","homedir","join","homedir","join","homedir","join","homedir","join","homedir","join","homedir","join","homedir","join","homedir","join","join","homedir","matter","existsSync","join","homedir","path","existsSync","readFileSync","mkdirSync","init_provider","migrateSubdirsToFlat","projectDir","getAllObservations","getAllAliasGroups","resolveObservations","getActiveSession","compressNarrative","suggestTopicKey","getRetentionSummary","getArchiveCandidates","rankByRelevance","archiveExpired","search","homedir","join","readFile","observations","lines","SkillsEngine","loadObservationsJson","path","promoteToMiniSkill","loadAllMiniSkills","deleteMiniSkill","formatMiniSkillsForInjection","findConsolidationCandidates","executeConsolidation","startSession","recordMiniSkillUsage","endSession","getSessionContext","listSessions","exportAsJson","exportAsMarkdown","importFromJson","exec","fileURLToPath","startDashboard","AgentRegistry","MessageBus","FileLockRegistry","TaskManager","TeamPersistence","getHookStatus","installHooks","detectInstalledAgents","access","deduplicateMemory","count"]}
|